arcpy.management.ChangeVersion BRANCH not working in toolbox

999
12
04-24-2023 08:06 AM
Labels (3)
HervéW
New Contributor II

Hi,

When trying to change the version of a BRANCH service feature class in ArcGIS Pro 2.9.8 with following line of code : arcpy.management.ChangeVersion(in_features=Canalisations_GAZ, version_type="BRANCH", version_name="sde.DEFAULT", date="", include_participating="INCLUDE"), it works well when executed from the Python window or using Change Version (Data Management)—ArcGIS Pro | Documentation in the Geoprocessing window.

But when trying to execute the same line of code in a Python script in a toolbox, no error is triggered, but the Feature Service Feature Class is not changed to the sde.DEFAULT version.

Is there any limitation in using that line of code inside a toolbox ?

I already searched the community forum and this behavior is mentioned in some posts, but without any solution.

The purpose is to have the possibility to change the version of BRANCH service feature classes from one version to another (DEFAULT or not).

Any clue on this issue ?

Regards,

Hervé

0 Kudos
12 Replies
RudraniChakraborty
New Contributor II

Hello @HervéW 

Are you trying the change version with the below code snippet?

arcpy.management.ChangeVersion(in_features, version_type, {version_name}, {date}, {include_participating})

 Since it is Branch Versioned feature service. Could you try to change the version manually? Switch to List by data source view >> Right click on sde.default >> change version >> select the child version. do we see any error?

community.PNG

HervéW
New Contributor II

Hello @RudraniChakraborty 

When I change the version using "Change version" menu in ArcGIS Pro, everything is working well.

I am also able to execute the following code inside the Python window in ArcGIS Pro :

proj=arcpy.mp.ArcGISProject('current')
for mp in proj.listMaps():
	for ly in mp.listLayers():
		if ly.isFeatureLayer:
			cnx=ly.connectionProperties
			if 'version' in cnx['connection_info']:
				url=cnx['connection_info']['url']
				v=cnx['connection_info']['version']
				if v!='sde.DEFAULT':
					arcpy.management.ChangeVersion(in_features=ly,version_type="BRANCH",version_name='sde.DEFAULT',include_participating='INCLUDE')
					print(f'switching from version {v} to sde.DEFAULT for layer {ly}')
					print(ly.connectionProperties['connection_info']['version'])

HervW_0-1684151936221.png

But when I put the same code inside a toolbox, it didn't work at all. The loop is executed, we can see in ArcGIS Pro that the code is trying to switch from one version to the default, but at the end all the layers stay inside the created version.

Regards,

Hervé

lkirbywrk
New Contributor

@HervéW Any luck with this? Trying to do something similar and experiencing same results as you.

0 Kudos
LanceKirby2
Occasional Contributor II

@HervéW Any luck with this? Trying to do something similar and experiencing same results as you.

0 Kudos
HervéW
New Contributor II

Hi,

We finally abandoned trying to change the version inside a toolbox, it seems it is not possible to do it this way. We keep using versions through ArcGIS Pro menu items.

Regards,

Hervé

0 Kudos
LanceKirby2
Occasional Contributor II

Thanks @HervéW. I figured out a solution. I can come back here and share it later. Signing off for the day.

0 Kudos
HervéW
New Contributor II

Hi Lance,

Don't hesitate to share your solution, maybe we can use it in our development.

Regards,

Hervé

0 Kudos
LanceKirby2
Occasional Contributor II

@HervéW so I have a python toolbox setup with a class/tool called VersionController. In its execute method I use arcpy.mp.ArcGISProProject('current') to grab the project object. I am passing that into an importing module (main.py) and I have another class called APRXVersionManager that takes this object as one of its instance attributes. Inside there I have two methods for switching from a verison to default and from default to a version. Instead of using the change version function, I am constructing dictionaries of the default and version connection info properties and just updating those in a loop. 

To get the version GUID needed for the class below, you could just use the python api to get the version, and look it up in the objects properties.

I did not test it, but just grabbing the Project object within the tool itself, and passing that into what ever module you need to may work with the ChangeVersion method.

 

class AprxVersionManager:
    def __init__(self, aprx_obj: str, version_name: str, version_guid: str) -> None:
        self.aprx_obj = aprx_obj
        self.version_name = version_name
        self.version_guid = version_guid
        self.map_obj = self.aprx_obj.listMaps("Map")[0]
        self.layers = [
            {
                "layer_name": "myFirstLayer",
                "layer_id": "0",
                "current_layer_obj": self.map_obj.listLayers("myFirstLayer")[0],
            },
            {
                "layer_name": "mySecondLayer",
                "layer_id": "1",
                "current_layer_obj": self.map_obj.listLayers("mySecondLayer")[0],
            },
            {
                "layer_name": "myThirdLayer",
                "layer_id": "2",
                "current_layer_obj": self.map_obj.listLayers("myThirdLayer")[0],
            },
        ]

    def get_default_lyr_conn_dict(self, layer_id: str):
        return {
            "connection_info": {
                "url": "https://domain.com/path/to/featureservice",
                "version": "sde.DEFAULT",
                "versionguid": "{CF8A9817-9A00-41AC-B0CC-58F78DBAE0A1}",
            },
            "dataset": f"{layer_id}",
            "workspace_factory": "FeatureService",
        }

    def get_version_lyr_conn_dict(self, layer_id: str):
        return {
            "connection_info": {
                "url": "https://domain.com/path/to/featureservice",
                "version": f"{self.version_name}",
                "versionguid": f"{self.version_guid}",
            },
            "dataset": f"{layer_id}",
            "workspace_factory": "FeatureService",
        }

    def switch_to_default(self):
        for layer in self.layers:
            default_lyr_conn_dict = self.get_default_lyr_conn_dict(
                layer_id=layer["layer_id"]
            )
            version_lyr_conn_dict = self.get_version_lyr_conn_dict(
                layer_id=layer["layer_id"]
            )

            layer["current_layer_obj"].updateConnectionProperties(
                version_lyr_conn_dict, default_lyr_conn_dict
            )

    def switch_to_version(self):
        for layer in self.layers:
            default_lyr_conn_dict = self.get_default_lyr_conn_dict(
                layer_id=layer["layer_id"]
            )
            version_lyr_conn_dict = self.get_version_lyr_conn_dict(
                layer_id=layer["layer_id"]
            )

            layer["current_layer_obj"].updateConnectionProperties(
                default_lyr_conn_dict, version_lyr_conn_dict
            )

 

0 Kudos
wilmoreno
New Contributor
from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection

class AprxChangeVersion:
   
    def __init__(self, aprx_obj: str, map_name: str, url_fs: str, version_name: str, version_guid: str) -> None:
        self.aprx_obj = aprx_obj
        self.url_fs = url_fs
        self.version_name = version_name
        self.version_guid = version_guid
        self.map_obj = self.aprx_obj.listMaps(map_name)[0]
        self.layers_tables = []
        for lyr in self.map_obj.listLayers():
            self.layers_tables.append({"layer_name":lyr.name, "layer_id":lyr.connectionProperties["dataset"], "current_layer_obj":lyr})
        for lyr in self.map_obj.listTables():
            self.layers_tables.append({"layer_name":lyr.name, "layer_id":lyr.connectionProperties["dataset"], "current_layer_obj":lyr})

    def get_default_lyr_conn_dict(self, layer_id: str, layer😞
        return {
            "connection_info": {
                "url": self.url_fs,
                "version": layer.connectionProperties["connection_info"]["version"],
                "versionguid": layer.connectionProperties["connection_info"]["versionguid"],
            },
            "dataset": f"{layer_id}",
            "workspace_factory": "FeatureService",
        }

    def get_version_lyr_conn_dict(self, layer_id: str😞
        return {
            "connection_info": {
                "url": self.url_fs,
                "version": f"{self.version_name}",
                "versionguid": f"{self.version_guid}",
            },
            "dataset": f"{layer_id}",
            "workspace_factory": "FeatureService",
        }

    def switch_to_default(self😞
        for layer in self.layers_tables:
            default_lyr_conn_dict = self.get_default_lyr_conn_dict(
                layer_id=layer["layer_id"]
            )
            version_lyr_conn_dict = self.get_version_lyr_conn_dict(
                layer_id=layer["layer_id"]
            )

            layer["current_layer_obj"].updateConnectionProperties(
                # version_lyr_conn_dict, default_lyr_conn_dict
                None, default_lyr_conn_dict
            )

    def switch_to_version(self😞
        for layer in self.layers_tables:
            # default_lyr_conn_dict = self.get_default_lyr_conn_dict(
            #     layer_id=layer["layer_id"]
            # )
            version_lyr_conn_dict = self.get_version_lyr_conn_dict(
                layer_id=layer["layer_id"]
            )

            layer["current_layer_obj"].updateConnectionProperties(
                # default_lyr_conn_dict, version_lyr_conn_dict
                None, version_lyr_conn_dict
            )
        self.aprx_obj.save()

def change_version():
    print("change_version...")
    gis = GIS("pro")
    name_version = "VERSION_TEST"
    versionNameProcess = "{}.2024_{}".format(gis.users.me.username, name_version)
    for lyr in active_map.listLayers():
        arcpy.management.ChangeVersion(lyr, "BRANCH", version_name=versionNameProcess)
    for lyr in active_map.listTables():
        arcpy.management.ChangeVersion(lyr, "BRANCH", version_name=versionNameProcess)
    aprx.save()
    version_ok = True
    for lyr in active_map.listLayers():
        if lyr.connectionProperties["connection_info"]["version"] != versionNameProcess:
            version_ok = False
            print(f"Error change version {lyr.name}. Se utilizara otro metodo")
            break
    if version_ok is False:
        print("change version AprxChangeVersion...")
        serviceItemId = ""
        gisContentParcelService = gis.content.get(serviceItemId)
        p_flc = FeatureLayerCollection.fromitem(gisContentParcelService)
        version_manager = p_flc.versions
        version = version_manager.get(version=versionNameProcess)
        version_guid = version.properties.versionGuid
        arc_cv = AprxChangeVersion(aprx, "MAP_RTL", gisContentParcelService.url, versionNameProcess, version_guid)
        arc_cv.switch_to_version()
    return True


if __name__ == '__main__':
    change_version()
0 Kudos