ArcMap이 편집 세션에 있는지 ArcPy를 통해 확인합니까?


11

한 기능 클래스 속성을 다른 기능 클래스 속성으로 복사하여 동료 워크 플로우 속도를 높이는 Python 추가 기능 버튼을 만들었습니다. arcpy.UpdateCursor 함수를 사용하여 대상 피처 클래스에서 행을 업데이트합니다. 현재 존재하는 것처럼이 버튼 스크립트는 편집 모드에 관계없이 실행될 수 있습니다. 분명히 편집 세션에서 실행될 때 사용자는 편집을 중지하고 변경 사항을 저장하지 않도록 선택할 수 있지만 스크립트가 편집 세션 외부에서 실행될 때는 그렇지 않습니다.

ArcMap이 현재 편집 세션에 있지 않은 경우 스크립트 실행을 중지하는 확인을 스크립트에 추가하려면 어떻게해야합니까?

이것은 ArcMap 10 & 10.1과 관련이 있습니다


또한 다른 ArcMap 사용자와 확인하여 편집 세션을 거치지 않고 테이블 업데이트가 일반적으로 허용되지 않는지 확인하고 싶습니다.

그렇다면이 스크립트는 편집 세션 밖에서 어떻게 실행됩니까?

이 스크립트는 또한 목록에서 두 번째 피처 클래스 테이블을 업데이트 할 때 나에게 도움이되는 ArcMap이 수행하는 겉보기에 우연한 선택 순서에 대한 또 다른 질문을 제기합니다. 그러나 그것은 다른 날입니다.

다음은 현재 작동하는 스크립트입니다 (10.1 편집기 구현없이).

사용자가 편집 세션에 있는지 확인하는 방법?

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

데이터 액세스 모듈 편집기는 표준 편집기와 독립적으로 작동하는 것 같습니다. 활성 편집 세션 테스트에 대한 추가 아이디어를 환영합니다. -Karl
KarlJr

좀 더 정보를 제공해 줄 수 있습니까? 모듈을 탐색하지 않은 우리를 위해이 결론을 이끌어 낸 이유는 무엇입니까?
Jay Laura

답변:


6

이 게시물을 기반으로 한 일반적인 기능은 다음과 같습니다.

어쩌면 이것은 ArcObjects 솔루션보다 조금 더 어색하지만 어려울 것 같습니다! 단순함이 복잡한 것보다 낫습니다. 그렇지 않은 경우를 제외하고.

사용법 예 :

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

암호:

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 좋은 개념이지만 OP는 편집 세션이 아닌 경우 중지 하고 편집 세션에 있으면 계속 하고 싶습니다 . 당신의 대답은 정반대입니다. 아마도 그것을 돌리는 데별로 걸리지 않을 것입니다.
Midavalo

OP는 이미 그의 문제를 해결했습니다.이 게시물은 더 일반적으로 유용한 기능으로 장식되어 있습니다. 함수 사용 방법에 대해 더 명확하게 예제를 수정했습니다.
커티스 가격

4

이 문제에 대한 나의 해결책은 Arcpy Addin Toolbar에 사용 가능한 확장을 사용하는 것이 었습니다. 편집 세션이 시작되거나 끝나는 것을 듣는 확장을 추가했습니다. 바의 모든 버튼을 : self.enable = False "로 설정 한 다음 편집 세션을 시작하거나 중지하여이 버튼을 활성화 또는 비활성화합니다.

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

시도해 볼만한 솔루션처럼 보입니다. 감사합니다
user18412

4

ArcObjects와 Python을 함께 사용하여 ArcMap에서 Editor의 상태를 확인하는 새로운 방법을 배웠기 때문에 다른 답변을 게시하고 있습니다. 내 대답은 Mark Cederholm이 수행 한 작업에서 많은 돈을 빌립니다 . Matt Wilkie의 "Snippits.py"파일에서 제공하는 코드 예제 및 comtypes를 다운로드하여 설치 한 다음 Snippets.py 스크립트 사본을 얻으려면 첫 번째 답변에 제공된 지침을 따라야합니다. 아래 스크립트에서 필수 기능의 사본을 게시하고 있습니다.

ArcMap_GetEditSessionStatus () 함수가 호출되면 ArcMap에서 에디터의 현재 상태를 확인하고 true 또는 false를 반환합니다. 이를 통해 사용자가 내 도구를 사용할 준비가되었는지 또는 편집 세션을 시작하라는 메시지가 표시되는지 확인할 수 있습니다. 이 방법의 단점은 Python에서 ArcObject를 사용하기 전에 comtype을 설치해야하기 때문에 다중 사용자 사무실 환경에서이 패키지가 필요한 도구를 공유하지 못할 수 있습니다. 제한된 경험으로 Esri Python 도구 추가 기능으로 쉽게 공유 할 수 있도록 모두 묶는 방법을 잘 모르겠습니다. 이 작업을 수행하는 방법에 대한 제안을 부탁드립니다.

#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
이것은 잘 작동합니다. 나는 이것이 오래된 게시물이라는 것을 알고 있지만, 이것을 이식하여 더 이식성이 좋으면 snippets 모듈을 python 패키지 로 만들고 그 안에 comtypes를 포함시킬 수 있습니다. 나는 회사를 위해이 작업을 수행하고 모든 사용자 지정 Python 모듈을 네트워크 공유에 배치했습니다. 누군가 ArcGIS 소프트웨어를 설치 / 재설치 할 때마다 파일을 수정 Desktop.pth하여 네트워크 공유에 대한 전체 경로를 포함하도록 배치 파일을 실행 하도록하여 모든 사람이 자동으로 모든 것을 가져올 수 있습니다.
crmackey

2

데이터 액세스 모듈을 사용하는 것은 어떻습니까? 이 모듈로 편집 세션을 시작할 수있는 것 같습니다.

몇 가지주의 사항 :

  1. 이 모듈을 시도하지 않았으며 10.0과 호환되는지 확실하지 않습니다. (10.1의 새로운 기능?)
  2. 예 1은 with명령문 사용을 보여줍니다 . 잠재적 예외를 잘 처리하므로 구현하기에 좋은 패러다임입니다.
  3. try / except명령문 에서 편집 세션을 시작하여 편집 세션이 이미 존재하는지 테스트 할 수 있습니다 .

이 프로젝트를 시작할 때 실제로 데이터 액세스 모듈에서 Editor 클래스를 사용하는 것으로 시작했지만 사용하는 것은 중요하지 않은 것 같습니다. 스크립트에 "arpy.da.Editor (workspace) with edit :"를 포함 시키면 편집기가 활성화되지 않았고 stopOperation / stop.Editing을 시도해도 편집기가 중지되지 않았습니다. 그러나 내가 잘못하고있을 수 있습니다 ...
user18412

1

그래서 이것은 내 도구를 사용하는 사람이 편집 세션에 있는지 여부를 제어 할 수없는 문제를 해결 한 방법입니다.

#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

스크립트는 나중에 스크립트에서 다른 UpdateCursor가있는 레이어에 UpdateCursor를 만들려고하기 때문에 작동합니다. 이는 데이터 액세스 모듈의 동작을 위반합니다. arcpy.da.UpdateCursor의 ESRI 리소스 페이지에 따르면 :

"다른 커서를 사용하여 동일한 작업 공간에서 동시 삽입 및 / 또는 업데이트 작업을 열려면 편집 세션을 시작해야합니다."

이 솔루션은 적절한 arcpy 스크립팅이라고 생각하는 것보다 더 해킹이기 때문에이 솔루션에 만족하지 않습니다. 더 나은 아이디어가 있습니까?


1
이것은 단지 아이디어이지만 ArcObjects에서 Editor 객체에 액세스하여 Arcpy에서 누락 된 것으로 보이는 EditState 속성을 확인할 수 있습니까? 파이썬에서 ArcObject를 조작하려고 시도한 적이 없지만이 스레드 는 그것을 수행하는 방법에 대해 이야기합니까?
Hornbydd
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.