11 votos

¿Comprobación a través de ArcPy si ArcMap está en sesión de edición?

He creado un botón de complemento de Python que ayuda a acelerar el flujo de trabajo de mis compañeros de trabajo copiando un atributo de clase de característica a otro. Utiliza la función arcpy.UpdateCursor para actualizar una fila en la clase de característica de destino. Tal y como existe ahora, este script de botón se puede ejecutar independientemente del modo de edición. Obviamente, cuando se ejecuta en una sesión de edición, el usuario puede optar por detener la edición y no guardar los cambios, pero este no es el caso cuando el script se ejecuta fuera de una sesión de edición.

¿Cómo puedo añadir una comprobación a la secuencia de comandos que impida su ejecución si ArcMap no se encuentra actualmente en una sesión de edición?

Esto afecta a ArcMap 10 y 10.1


También quiero consultar con otros usuarios de ArcMap para verificar que las actualizaciones de las tablas no se permite normalmente sin estar en una sesión de edición.

Entonces, ¿cómo se ejecuta este script fuera de una sesión de edición?

Esta secuencia de comandos también trae a colación otra cuestión sobre el orden de selección aparentemente serendipia ArcMap realiza que sólo pasa a trabajar para mí cuando actualizo la 2 ª tabla de clases de características de una lista, pero eso es para otro día.

Aquí está el script tal y como funciona ahora (sin ninguna implementación del editor 10.1):

¿Cómo añadir una comprobación para asegurar que el usuario está en una sesión de edición?

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

0 votos

El editor del módulo de acceso a datos parece funcionar independientemente del editor estándar. Agradecería cualquier idea adicional sobre las pruebas para una sesión de edición activa. -Karl

0 votos

¿Puede darnos más información? ¿Qué le ha llevado a esta conclusión para los que no hemos explorado el módulo?

6voto

Lazer Puntos 3926

He aquí una función genérica basada en este post.

Puede que esta solución sea un poco más chapucera que la de ArcObjects, pero parece mucho menos complicada. Lo simple es mejor que lo complejo. Excepto cuando no lo es.

Ejemplo de uso:

if CheckEditSession(tbl):
    print("An edit session is currently open.")

código:

def CheckEditSession(lyr):
    """Check for an active edit session on an fc or table.
    Return True of edit session active, else False"""
    edit_session = True
    row1 = None
    try:
        # attempt to open two cursors on the input
        # this generates a RuntimeError if no edit session is active
        OID = arcpy.Describe(lyr).OIDFieldName
        with arcpy.da.UpdateCursor(lyr, OID) as rows:
            row = next(rows)
            with arcpy.da.UpdateCursor(lyr, OID) as rows2:
                row2 = next(rows2)
    except RuntimeError as e:
        if e.message == "workspace already in transaction mode":
            # this error means that no edit session is active
            edit_session = False
        else:
            # we have some other error going on, report it
            raise
    return edit_session

4voto

F_Kellner Puntos 179

Mi solución a este problema fue utilizar las extensiones disponibles para Arcpy Addin Toolbar. He añadido una extensión que escucha para una sesión de edición para comenzar o terminar. Tengo todos mis botones en el conjunto de barras a :self.enable = False" para empezar y luego estos botones son entonces activar o desactivar al iniciar o detener una sesión de edición.

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):
        ......

0 votos

Parece una solución que merece la pena probar. Muchas gracias.

4voto

user18412 Puntos 104

Estoy publicando otra respuesta porque he aprendido un nuevo método para comprobar el estado del Editor en ArcMap utilizando ArcObjects y Python juntos. Mi respuesta toma prestado en gran medida del trabajo realizado por Mark Cederholm como se hace referencia en este post: ¿Cómo acceder a ArcObjects desde Python? y ejemplos de código proporcionados por Matt Wilkie en su archivo "Snippits.py". Deberá seguir las instrucciones proporcionadas en la primera respuesta para descargar e instalar comtypes y, a continuación, obtener una copia del script Snippets.py. A continuación voy a publicar una copia de las funciones esenciales de ese script.

Cuando se llama a la función ArcMap_GetEditSessionStatus(), ésta comprobará el estado actual del Editor en ArcMap y devolverá true o false. Esto me permite comprobar si un usuario está preparado para utilizar mi herramienta o si necesita que se le pida que inicie una sesión de edición. La desventaja de este método es el requisito de instalar comtypes antes de que ArcObjects se pueda utilizar en Python, por lo que compartir una herramienta que requiere este paquete en un entorno de oficina multiusuario podría no ser posible. Con mi limitada experiencia, no estoy seguro de cómo agruparlo todo para compartirlo fácilmente como un complemento de la herramienta Esri Python. Agradecería cualquier sugerencia al respecto.

#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

1 votos

Esto funciona muy bien. Sé que este es un post viejo, pero si quieres empaquetar esto para que sea más portable, puedes hacer el módulo de fragmentos como un paquete python e incluir comtipos en él. Hago esto para mi empresa y he colocado todos nuestros módulos Python personalizados en un recurso compartido de red. Cada vez que alguien instala / reinstala el software ArcGIS, tengo que ejecutar un archivo por lotes que modifica su Desktop.pth para incluir la ruta completa al recurso compartido de red, de modo que todos puedan importar todo automáticamente.

2voto

Jorge Córdoba Puntos 18919

¿Qué le parece utilizar el módulo de acceso a datos ? Parece que puedes iniciar una sesión de edición con este módulo.

Algunas advertencias:

  1. No he probado este módulo y el no estoy seguro de si es 10.0 compatible. (¿Es nuevo en 10.1?)
  2. El ejemplo 1 muestra el uso de un with declaración. Este es un gran paradigma para implementar, ya que maneja las excepciones potenciales bien.
  3. Tal vez pueda comprobar si ya existe una sesión de edición intentando iniciar una en un try / except declaración.

0 votos

En realidad empecé con el uso de la clase Editor en el módulo de acceso a datos cuando empecé este proyecto, pero su uso no parecía importar. Incluyendo "with arcpy.da.Editor(workspace) as edit:" en mi script no activaba el editor, y probando stopOperation/stop.Editing no paraba el editor. Pero podría estar haciéndolo mal...

1voto

user18412 Puntos 104

Así es como solucioné mi problema de no poder controlar si alguien que usaba mi herramienta estaba en una sesión de edición o no:

#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

El script funciona porque intenta crear un UpdateCursor en una capa que tiene otro UpdateCursor más adelante en el script. Esto viola el comportamiento del módulo de acceso a datos. De acuerdo con la página de Recursos ESRI en arcpy.da.UpdateCursor:

"La apertura de operaciones simultáneas de inserción y/o actualización en el mismo espacio de trabajo utilizando cursores diferentes requiere el inicio de una sesión de edición."

No estoy contento con esta solución porque es más un hack que lo que imagino es un scripting arcpy adecuado. ¿Mejores ideas alguien?

1 votos

Esto es sólo una idea, pero usted podría tratar de acceder al objeto Editor en ArcObjects y comprobar su propiedad EditState que parece ser lo que falta en arcpy? Nunca he tratado de manipular ArcObjects de python, pero esto hilo habla de cómo hacerlo?

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X