Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I've created a Python add-in button that helps speed up my coworkers workflow by copying one feature class attribute to another. It uses the arcpy.UpdateCursor function to update a row in the target feature class. As it exists now, this button script can be run regardless of the editing mode. Obviously when its run in an edit session, the user can choose to stop editing and not save changes, but this is not the case when the script runs outside of an edit session.

How can I add a check to the script that will stop the script from running if ArcMap is not currently in an edit session?

This concerns ArcMap 10 & 10.1

Thanks for any ideas

Update: I also want to check with other ArcMap users to verify that updates to tables is not normally allowed without being in an edit session. So how is this script running outside of an edit session? This script also brings up another question about the seemingly serendipitous selection order ArcMap performs that just happens to work for me when I update the 2nd feature class table from a list, but that's for another day...

Here's the script as it works now (without any 10.1 editor implementation): How to add a check to ensure the user is in an edit session?

def onClick(self):
    #Reference mxd
    mxd = arcpy.mapping.MapDocument("CURRENT")
    #Reference the main Data frame
    mm = arcpy.mapping.ListDataFrames(mxd, "MainMap")[0]
    #Reference the Water System Valve feature class
    waterValves = arcpy.mapping.ListLayers(mxd, "Water System Valve", mm)[0]
    #Reference the fire hydrant feature class
    fireHydrants = arcpy.mapping.ListLayers(mxd, "Water Hydrant", mm)[0]

    #Use the extent of the main DF to select all valves in the current view
    dfAsFeature = arcpy.Polygon(arcpy.Array([mm.extent.lowerLeft, mm.extent.lowerRight, mm.extent.upperRight, mm.extent.upperLeft]), mm.spatialReference)
    arcpy.SelectLayerByLocation_management(waterValves, "WITHIN", dfAsFeature,"", "NEW_SELECTION")

    arcpy.SelectLayerByAttribute_management(waterValves, "SUBSET_SELECTION", "LOCATIONID IS NULL")

    fields = ["LOCATIONID"]

    row, rows = None, None
    rows = arcpy.UpdateCursor(waterValves,fields)
    row = rows.next()
    valveList = []
    append = valveList.append

    #Loop through the valves table to update LocationID
    while row:
        builder = str(row.QSNO)+"-"+ str(row.VALVESEQNO)
        row.setValue("LOCATIONID", builder)
        append(builder)
        rows.updateRow(row)
        row = rows.next()

    del row, rows

    #New selection for fire hydrants
    arcpy.SelectLayerByLocation_management(fireHydrants, "WITHIN", dfAsFeature,"", "NEW_SELECTION")
    arcpy.SelectLayerByAttribute_management(fireHydrants, "SUBSET_SELECTION", "LOCATIONID IS NULL")

    row, rows = None, None
    rows = arcpy.UpdateCursor(fireHydrants,fields)
    row = rows.next()

    #Loop through fire hydrant table to update LocationID
    while row:
        for locID in valveList:
            construct = str(locID) + "-FH"
            #print construct
            row.setValue("LOCATIONID", construct)
            rows.updateRow(row)
            row = rows.next()

    del row, rows, valveList, mxd
share|improve this question
    
The data access module editor seems to operate independent of the standard Editor. I would welcome any additional ideas on testing for an active edit session. -Karl –  KarlJr May 31 '13 at 14:06
    
Can you provide a little more info? What led you to this conclusion for those of us that have not explored the module? –  Jay Laura May 31 '13 at 14:15

4 Answers 4

My solution to this problem was to use the extensions available for the Arcpy Addin Toolbar. I added an extension that listens for an edit session to begin or end. I have all of my buttons on the bar set to :self.enable = False" to start with and then these buttons are then either enable or disabled by starting or stop an edit session.

class Active_Edit_Session(object):
"""Implementation for NEZ_EDITS_addin.Listen_for_Edit_Session (Extension)"""
def __init__(self):
    self.enabled = True
def onStartEditing(self):
    button_3100.enabled=True    
def onStopEditing(self, save_changes):
    button_3100.enabled=False

class LFM_3100(object):
    """Implementation for LFM_3100.button_3100 (Button)"""
    def __init__(self):
        self.enabled = False
        self.checked = False
    def onClick(self):
        ......
share|improve this answer
    
This looks like a solution worth trying. Thank you –  user18412 Nov 8 '13 at 14:53

How about using the data access module? It looks like you can start an edit session with this module.

A few caveats:

  1. I have not tried this module and the am not sure if it is 10.0 compatible. (New in 10.1?)
  2. Example 1 shows the use of a with statement. This is a great paradigm to implement as it handles potential exceptions well.
  3. You might be able to test if an edit session is already live by attempting to launch one in a try / except statement.
share|improve this answer
    
Great answer - and arcpy.da is new at 10.1 so I think that is the version @user18412 will need to focus on. I too have not tried the Editor class yet. –  PolyGeo May 23 '13 at 21:16
    
I actually started with using the Editor class in the data access module when I began this project but using it didn't seem to matter. Including "with arcpy.da.Editor(workspace) as edit:" in my script didn't activate the editor, and trying stopOperation/stop.Editing didn't stop the editor. But I could be doing it wrong... –  user18412 May 23 '13 at 21:18
    
@user18412 How about editing your question with a code snippet to show your implementation? –  Jay Laura May 23 '13 at 21:20
    
Ok, code added. –  user18412 May 23 '13 at 22:05
up vote 1 down vote accepted

So this is how I fixed my issue of not being able to control if someone using my tool was in an edit session or not:

#Reference to mxd and layers script here. Then...
try:
    fields = ("OBJECTID")
    upCursor = arcpy.da.UpdateCursor(waterValves, fields)
    with upCursor as cursor:
        for row in cursor:
            pass
except:
    pythonaddins.MessageBox('You are not in an edit session', 'Warning', 0)

else:
#Rest of script

The script works because it tries to create an UpdateCursor on a layer that has another UpdateCursor later in the script. This violates the behavior of the data access module. According to the ESRI Resources page on arcpy.da.UpdateCursor:

"Opening simultaneous insert and/or update operations on the same workspace using different cursors requires the start of an edit session."

I'm not happy with this solution because it's more of a hack than what I imagine is proper arcpy scripting. Better ideas anyone?

share|improve this answer
1  
This is just an idea but you could try accessing the Editor object in ArcObjects and check its property EditState which seems to be what is missing from arcpy? I've never tried to manipulate ArcObjects from python but this thread talks about how to do it? –  Hornbydd Nov 8 '13 at 13:11

I'm posting another answer because I've learned a new method for checking the status of the Editor in ArcMap using ArcObjects and Python together. My answer borrows heavily from the work done by Mark Cederholm as referenced in this post: How do I access ArcObjects from Python?, and code examples provided by Matt Wilkie in his "Snippits.py" file. You will need to follow the instructions provided in the first answer to download and install comtypes and then get a copy of the Snippets.py script. I am posting a copy of the essential functions from that script below.

When the function ArcMap_GetEditSessionStatus() is called, it will check the current state of the Editor in ArcMap and return true or false. This lets me check if a user is prepared to use my tool or if they need to be prompted to start an edit session. The downside to this method is the requirement to install comtypes before ArcObjects can be used in Python, so sharing a tool that requires this package in a multi-user office environment might not be possible. With my limited experience I'm not sure how to bundle it all together for easy sharing as an Esri Python tool add-in. Suggestions for how to do this would be appreciated.

#From the Snippits.py file created by Matt Wilkie
def NewObj(MyClass, MyInterface):
    """Creates a new comtypes POINTER object where\n\
    MyClass is the class to be instantiated,\n\
    MyInterface is the interface to be assigned"""
    from comtypes.client import CreateObject
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        return None

def CType(obj, interface):
    """Casts obj to interface and returns comtypes POINTER or None"""
    try:
        newobj = obj.QueryInterface(interface)
        return newobj
    except:
        return None

def CLSID(MyClass):
    """Return CLSID of MyClass as string"""
    return str(MyClass._reg_clsid_)

def GetApp(app="ArcMap"):
    """app must be 'ArcMap' (default) or 'ArcCatalog'\n\
    Execute GetDesktopModules() first"""
    if not (app == "ArcMap" or app == "ArcCatalog"):
        print "app must be 'ArcMap' or 'ArcCatalog'"
        return None
    import comtypes.gen.esriFramework as esriFramework
    import comtypes.gen.esriArcMapUI as esriArcMapUI
    import comtypes.gen.esriCatalogUI as esriCatalogUI
    pAppROT = NewObj(esriFramework.AppROT, esriFramework.IAppROT)
    iCount = pAppROT.Count
    if iCount == 0:
        return None
    for i in range(iCount):
        pApp = pAppROT.Item(i)
        if app == "ArcCatalog":
            if CType(pApp, esriCatalogUI.IGxApplication):
                return pApp
            continue
        if CType(pApp, esriArcMapUI.IMxApplication):
            return pApp
    return None


def GetModule(sModuleName):
    """Import ArcGIS module"""
    from comtypes.client import GetModule
    sLibPath = GetLibPath()
    GetModule(sLibPath + sModuleName)


def GetDesktopModules():
    """Import basic ArcGIS Desktop libraries"""
    GetModule("esriFramework.olb")
    GetModule("esriArcMapUI.olb")

#My added function for checking edit session status
def ArcMap_GetEditSessionStatus():

    GetDesktopModules()
    GetModule("esriEditor.olb")
    import comtypes.gen.esriSystem as esriSystem
    import comtypes.gen.esriEditor as esriEditor
    pApp = GetApp()
    pID = NewObj(esriSystem.UID, esriSystem.IUID)
    pID.Value = CLSID(esriEditor.Editor)
    pExt = pApp.FindExtensionByCLSID(pID)
    pEditor = CType(pExt, esriEditor.IEditor)
    if pEditor.EditState == esriEditor.esriStateEditing:
        print "Edit session active"
        return True
    else:
        print "Not in an edit session"
        return False
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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