Memeriksa melalui ArcPy jika ArcMap dalam sesi edit?

11

Saya telah membuat tombol tambah Python yang membantu mempercepat alur kerja rekan kerja saya dengan menyalin satu atribut kelas fitur ke atribut lainnya. Ini menggunakan fungsi arcpy.UpdateCursor untuk memperbarui baris di kelas fitur target. Seperti yang ada sekarang, skrip tombol ini dapat dijalankan terlepas dari mode pengeditan. Jelas ketika dijalankan dalam sesi edit, pengguna dapat memilih untuk berhenti mengedit dan tidak menyimpan perubahan, tetapi ini tidak terjadi ketika skrip berjalan di luar sesi edit.

Bagaimana saya bisa menambahkan tanda centang pada skrip yang akan menghentikan skrip agar tidak berjalan jika ArcMap saat ini tidak dalam sesi edit?

Ini menyangkut ArcMap 10 & 10.1


Saya juga ingin memeriksa dengan pengguna ArcMap lain untuk memverifikasi bahwa pembaruan tabel biasanya tidak diizinkan tanpa berada dalam sesi edit.

Jadi bagaimana skrip ini berjalan di luar sesi edit?

Script ini juga memunculkan pertanyaan lain tentang urutan seleksi ArcMap yang tampaknya kebetulan bekerja untuk saya ketika saya memperbarui tabel kelas fitur 2 dari daftar, tapi itu untuk hari lain.

Inilah skrip yang berfungsi sekarang (tanpa implementasi editor 10.1):

Bagaimana cara menambahkan cek untuk memastikan pengguna dalam sesi edit?

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
pengguna18412
sumber
Editor modul akses data tampaknya beroperasi independen dari Editor standar. Saya akan menyambut setiap ide tambahan tentang pengujian untuk sesi edit aktif. -Karl
KarlJr
Bisakah Anda memberikan sedikit info lebih lanjut? Apa yang mengarahkan Anda ke kesimpulan ini bagi kita yang belum menjelajahi modul ini?
Jay Laura

Jawaban:

6

Berikut adalah fungsi generik berdasarkan posting ini.

Mungkin ini sedikit lebih kludgy daripada solusi ArcObjects, tapi sepertinya jauh lebih mudah! Sederhana lebih baik daripada kompleks. Kecuali kalau tidak.

Contoh penggunaan:

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

kode:

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
Harga Curtis
sumber
+1 Konsep yang bagus, namun OP ingin berhenti jika tidak dalam sesi edit, dan melanjutkan jika itu dalam sesi edit. Jawaban Anda tampaknya melakukan yang sebaliknya. Mungkin tidak butuh banyak untuk membalikkan itu.
Midavalo
OP sudah menyelesaikan masalahnya, postingan ini hanyalah icing dengan fungsi yang lebih bermanfaat secara umum. Saya memodifikasi contoh saya agar lebih jelas tentang bagaimana fungsi tersebut digunakan.
Harga Curtis
4

Solusi saya untuk masalah ini adalah menggunakan ekstensi yang tersedia untuk Arcpy Addin Toolbar. Saya menambahkan ekstensi yang mendengarkan sesi edit untuk memulai atau mengakhiri. Saya memiliki semua tombol di bilah yang disetel ke: self.enable = False "untuk memulai dan kemudian tombol-tombol ini kemudian diaktifkan atau dinonaktifkan dengan memulai atau menghentikan sesi edit.

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):
        ......
F_Kellner
sumber
Ini sepertinya solusi yang patut dicoba. Terima kasih
user18412
4

Saya memposting jawaban lain karena saya telah mempelajari metode baru untuk memeriksa status Editor di ArcMap menggunakan ArcObjects dan Python bersama-sama. Jawaban saya meminjam sangat banyak dari pekerjaan yang dilakukan oleh Mark Cederholm sebagaimana dirujuk dalam posting ini: Bagaimana cara mengakses ArcObjects dari Python? , dan contoh kode yang diberikan oleh Matt Wilkie dalam file "Snippits.py". Anda harus mengikuti instruksi yang disediakan di jawaban pertama untuk mengunduh dan menginstal comtypes dan kemudian mendapatkan salinan skrip Snippets.py. Saya memposting salinan fungsi penting dari skrip di bawah ini.

Ketika fungsi ArcMap_GetEditSessionStatus () dipanggil, ia akan memeriksa keadaan Editor saat ini di ArcMap dan mengembalikan true atau false. Ini memungkinkan saya memeriksa apakah pengguna siap untuk menggunakan alat saya atau apakah mereka perlu diminta untuk memulai sesi edit. Kelemahan dari metode ini adalah persyaratan untuk menginstal comtypes sebelum ArcObjects dapat digunakan dengan Python, jadi berbagi alat yang memerlukan paket ini di lingkungan kantor multi-pengguna mungkin tidak dimungkinkan. Dengan pengalaman terbatas saya, saya tidak yakin bagaimana menggabungkan semuanya agar mudah dibagikan sebagai tambahan alat Esri Python. Saran untuk bagaimana melakukan ini akan sangat dihargai.

#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
pengguna18412
sumber
1
Ini sangat bagus. Saya tahu ini adalah posting lama, tetapi jika Anda ingin mengemas ini sehingga lebih portabel, Anda dapat membuat modul snippet sebagai paket python , dan memasukkan comtypes di dalamnya. Saya melakukan ini untuk perusahaan saya dan saya telah menempatkan semua modul Python kustom kami pada jaringan berbagi. Setiap kali seseorang menginstal / menginstal ulang perangkat lunak ArcGIS, saya minta mereka menjalankan file batch yang memodifikasi Desktop.pthfile mereka untuk memasukkan path lengkap ke share jaringan, sehingga semua orang dapat secara otomatis mengimpor semuanya.
crmackey
2

Bagaimana dengan menggunakan modul akses data ? Sepertinya Anda dapat memulai sesi edit dengan modul ini.

Beberapa peringatan:

  1. Saya belum mencoba modul ini dan saya tidak yakin apakah itu kompatibel dengan 10.0. (Baru dalam 10.1?)
  2. Contoh 1 menunjukkan penggunaan withpernyataan. Ini adalah paradigma yang bagus untuk diterapkan karena menangani potensi pengecualian dengan baik.
  3. Anda mungkin dapat menguji apakah sesi edit sudah aktif dengan mencoba meluncurkannya dalam sebuah try / exceptpernyataan.
Jay Laura
sumber
Saya benar-benar mulai dengan menggunakan kelas Editor dalam modul akses data ketika saya memulai proyek ini tetapi menggunakannya tampaknya tidak masalah. Termasuk "dengan arcpy.da.Editor (workspace) sebagai edit:" dalam skrip saya tidak mengaktifkan editor, dan mencoba stopOperation / stop.Editing tidak menghentikan editor. Tapi saya bisa salah ...
user18412
1

Jadi ini adalah bagaimana saya memperbaiki masalah saya karena tidak dapat mengontrol apakah seseorang menggunakan alat saya dalam sesi edit atau tidak:

#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

Skrip berfungsi karena mencoba membuat UpdateCursor pada layer yang memiliki UpdateCursor lain di skrip. Ini melanggar perilaku modul akses data. Menurut halaman Sumber Daya ESRI di arcpy.da.UpdateCursor:

"Membuka penyisipan dan / atau memperbarui operasi secara bersamaan pada ruang kerja yang sama menggunakan kursor berbeda memerlukan dimulainya sesi edit."

Saya tidak senang dengan solusi ini karena ini lebih merupakan hack daripada apa yang saya bayangkan adalah skrip arcpy yang tepat. Ide yang lebih baik?

pengguna18412
sumber
1
Ini hanya sebuah ide tetapi Anda dapat mencoba mengakses objek Editor di ArcObjects dan memeriksa properti EditState yang tampaknya merupakan apa yang hilang dari arcpy? Saya tidak pernah mencoba untuk memanipulasi ArcObjects dari python tetapi utas ini berbicara tentang bagaimana melakukannya?
Hornbydd