Verifica tramite ArcPy se ArcMap è in sessione di modifica?


11

Ho creato un pulsante aggiuntivo Python che aiuta ad accelerare il flusso di lavoro dei miei colleghi copiando un attributo della classe di funzionalità in un altro. Utilizza la funzione arcpy.UpdateCursor per aggiornare una riga nella classe di caratteristiche di destinazione. Come esiste ora, questo script di pulsanti può essere eseguito indipendentemente dalla modalità di modifica. Ovviamente quando viene eseguito in una sessione di modifica, l'utente può scegliere di interrompere la modifica e non salvare le modifiche, ma non è così quando lo script viene eseguito al di fuori di una sessione di modifica.

Come posso aggiungere un segno di spunta allo script che interromperà l'esecuzione dello script se ArcMap non è attualmente in una sessione di modifica?

Ciò riguarda ArcMap 10 e 10.1


Voglio anche verificare con altri utenti ArcMap per verificare che gli aggiornamenti alle tabelle non siano normalmente consentiti senza essere in una sessione di modifica.

Quindi come funziona questo script al di fuori di una sessione di modifica?

Questo script solleva anche un'altra domanda sull'ordine di selezione apparentemente fortuito che ArcMap esegue che funziona per me quando aggiorno la seconda tabella delle classi di funzionalità da un elenco, ma è per un altro giorno.

Ecco lo script come funziona ora (senza alcuna implementazione dell'editor 10.1):

Come aggiungere un segno di spunta per assicurarsi che l'utente sia in una sessione di modifica?

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

L'editor del modulo di accesso ai dati sembra funzionare indipendentemente dall'editor standard. Gradirei ulteriori idee sui test per una sessione di modifica attiva. -Karl
KarlJr

Puoi fornire qualche informazione in più? Cosa ti ha portato a questa conclusione per quelli di noi che non hanno esplorato il modulo?
Jay Laura,

Risposte:


6

Ecco una funzione generica basata su questo post.

Forse questo è un po 'più complicato della soluzione ArcObjects, ma sicuramente sembra molto meno seccante! Semplice è meglio di complesso. Tranne quando non lo è.

Esempio di utilizzo:

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

codice:

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

+1 Concetto piacevole, tuttavia l'OP vuole fermarsi se non in una sessione di modifica e continuare se si trova in una sessione di modifica. La tua risposta sembra fare il contrario. Forse non ci vorrebbe molto per capovolgerlo però.
Midavalo

L'OP ha già risolto il suo problema, questo post è solo una ciliegina sulla torta con una funzione generalmente più utile. Ho modificato il mio esempio per essere più chiaro su come viene utilizzata la funzione.
Curtis Price

4

La mia soluzione a questo problema era utilizzare le estensioni disponibili per la barra degli strumenti di Arcpy Addin. Ho aggiunto un'estensione che ascolta l'inizio o la fine di una sessione di modifica. Ho tutti i miei pulsanti sulla barra impostati su: self.enable = False "per iniziare e quindi questi pulsanti sono abilitati o disabilitati avviando o interrompendo una sessione di modifica.

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

Questa sembra una soluzione che vale la pena provare. Grazie
user18412

4

Sto postando un'altra risposta perché ho imparato un nuovo metodo per controllare lo stato dell'Editor in ArcMap usando ArcObjects e Python insieme. La mia risposta prende in prestito pesantemente dal lavoro svolto da Mark Cederholm come indicato in questo post: Come posso accedere ad ArcObjects da Python? e esempi di codice forniti da Matt Wilkie nel suo file "Snippits.py". Dovrai seguire le istruzioni fornite nella prima risposta per scaricare e installare i comtype e quindi ottenere una copia dello script Snippets.py. Sto postando una copia delle funzioni essenziali di quello script qui sotto.

Quando viene chiamata la funzione ArcMap_GetEditSessionStatus (), controllerà lo stato corrente dell'Editor in ArcMap e restituirà vero o falso. Questo mi consente di verificare se un utente è pronto a utilizzare il mio strumento o se deve essere richiesto di avviare una sessione di modifica. L'aspetto negativo di questo metodo è il requisito di installare i comtype prima che ArcObjects possa essere utilizzato in Python, quindi potrebbe non essere possibile condividere uno strumento che richiede questo pacchetto in un ambiente di ufficio multiutente. Con la mia esperienza limitata non sono sicuro di come raggruppare tutto insieme per una facile condivisione come componente aggiuntivo dello strumento Esri Python. Suggerimenti per come fare questo sarebbero apprezzati.

#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
Funziona benissimo. So che questo è un vecchio post, ma se vuoi impacchettarlo in modo che sia più portatile, puoi creare il modulo snippets come pacchetto python e includere al suo interno i comtype. Lo faccio per la mia azienda e ho inserito tutti i nostri moduli Python personalizzati su una condivisione di rete. Ogni volta che qualcuno installa / reinstalla il software ArcGIS, faccio eseguire un file batch che modifica il proprio Desktop.pthfile in modo da includere il percorso completo della condivisione di rete, in modo che tutti possano importare automaticamente tutto.
Crmackey,

2

Che ne dici di usare il modulo di accesso ai dati ? Sembra che tu possa iniziare una sessione di modifica con questo modulo.

Alcune avvertenze:

  1. Non ho provato questo modulo e non sono sicuro che sia compatibile 10.0. (Nuovo in 10.1?)
  2. L'esempio 1 mostra l'uso di withun'istruzione. Questo è un grande paradigma da implementare poiché gestisce bene le potenziali eccezioni.
  3. Potresti essere in grado di verificare se una sessione di modifica è già attiva tentando di avviarne una in try / exceptun'istruzione.

In realtà ho iniziato a utilizzare la classe Editor nel modulo di accesso ai dati quando ho iniziato questo progetto, ma il suo utilizzo non sembrava importare. Includendo "with arcpy.da.Editor (area di lavoro) come modifica:" nel mio script non è stato attivato l'editor, e provando stopOperation / stop.Editing non ha fermato l'editor. Ma potrei sbagliarmi ...
user18412

1

Quindi è così che ho risolto il problema di non poter controllare se qualcuno che utilizzava il mio strumento fosse in una sessione di modifica o meno:

#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

Lo script funziona perché tenta di creare un UpdateCursor su un livello che ha un altro UpdateCursor più avanti nello script. Ciò viola il comportamento del modulo di accesso ai dati. Secondo la pagina delle risorse ESRI su arcpy.da.UpdateCursor:

"L'apertura simultanea di operazioni di inserimento e / o aggiornamento sullo stesso spazio di lavoro utilizzando cursori diversi richiede l'avvio di una sessione di modifica."

Non sono contento di questa soluzione perché è più un hack di quello che immagino sia un corretto script arcpy. Idee migliori qualcuno?


1
Questa è solo un'idea ma potresti provare ad accedere all'oggetto Editor in ArcObjects e controllare la sua proprietà EditState che sembra essere ciò che manca a Arcpy? Non ho mai provato a manipolare ArcObjects da Python ma questo thread parla di come farlo?
Hornbydd,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.