Arcpy parameter for ArcGIS Pro Document

2555
6
Jump to solution
03-22-2021 12:24 PM
KennethEggering1
New Contributor II

Is there a way to specify a Pro-Doc as a parameter input to a Python Toolbox? I'm writing a tool that iterates over different layouts, and exports to PDF. It would be nice to allow users of the tool the ability to specify a ProDoc (e.g. "//file/path/prodoc.aprx" or "current"). It seems that arcpy for Pro has not been updated, as it still has an ArcMap option (dataType="DEMapDocument").

Snag_14f61161.png

 

0 Kudos
1 Solution

Accepted Solutions
KennethEggering1
New Contributor II

Perhaps not the most elegant solution, but here is what I went with in the end. Any comments or suggestions greatly appreciated. 

 

# -*- coding: utf-8 -*-
import arcpy, os

class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the .pyt file)."""
        self.label = "Toolbox"
        self.alias = ""
        # List of tool classes associated with this toolbox
        self.tools = [Tool]

class Tool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Tool"
        self.description = ""
        self.canRunInBackground = False
    
    currentList = ["CURRENT", "current"]

    def getParameterInfo(self):
        """Define parameter definitions"""
        
        param0 = arcpy.Parameter(displayName="Pro-Document", 
                                 name="proDocument", 
                                 datatype="GPString", 
                                 parameterType="Required", 
                                 direction="Input")
        
        param1 = arcpy.Parameter(displayName="Layout", 
                                 name="inlayout", 
                                 datatype="GPString", 
                                 parameterType="Required", 
                                 direction="Input")
        
        params = [param0, param1]
        
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal 
        validation is performed.  This method is called whenever a 
        parameter has been changed."""
        
        if parameters[0].value:
            p0Val = parameters[0].valueAsText
            if (p0Val.endswith(".aprx") and os.path.exists(p0Val)) or p0Val in self.currentList:
                aprx = arcpy.mp.ArcGISProject(parameters[0].valueAsText)
                layout_list = [l.name for l in aprx.listLayouts()]
                parameters[1].filter.list = layout_list

        return parameters
    
    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool parameter. 
        This method is called after internal validation."""
        
        if parameters[0].value:
            p0Val = parameters[0].valueAsText
            if not ((p0Val.endswith(".aprx") and os.path.exists(p0Val)) or p0Val in self.currentList):
                parameters[0].setErrorMessage("Not a valid ArcPro Document")

        return

    def execute(self, parameters, messages):
        """The source code of the tool."""
        aprx = arcpy.mp.ArcGISProject(parameters[0].valueAsText)
        arpxPath = str(os.path.normpath(aprx.filePath))
        arcpy.AddMessage(f"Pro-Doc Path: {arpxPath}")

        return

 

The main limitation is that the "Pro-Document" input parameter does not have the nifty folder icon (see red arrow) for users to click and navigate to the document. Users have to build/write a path string if not using "current."

Snag_1484366.png

 

 

View solution in original post

0 Kudos
6 Replies
nita14
by
Occasional Contributor III

Hi,

Why not to specify File as Data Type with .aprx extension? Does it work for you?

BR,

Adam

KennethEggering1
New Contributor II

Datatypes of "DEFile" and "GPString" can both work with limitations. Each allow users to enter errant inputs (e.g. .txt files, or random strings), which throws an error on subsequent parameter inputs that build off it. Easily enough for users to figure out I suppose. Would still be nice if ESRI added an ArcPro datatype, allowing users to open the folder icon pre-filtered with only .aprx files. 

Snag_15194d08.png

 

0 Kudos
Luke_Pinner
MVP Regular Contributor

Perhaps use DEFile and only allow aprx files using a filter:

 

def getParameterInfo(self):
    param0 = arcpy.Parameter(
        displayName="Input Project",
        name="in_project",
        datatype="DEFile",
        parameterType="Required",
        direction="Input")

    #  set the filter list to a list of file extension names
    param0.filter.list = ['aprx']

 

KennethEggering1
New Contributor II

Thanks for the tip @Luke_Pinner. The tool needed to be able to work in the "current" pro-document, so filtering by the aprx file extension didn't fully work for this situation. I opted to go with a parameter type of GPString and trap any errors in the updateParameters/updateMessages below.

0 Kudos
KennethEggering1
New Contributor II

Perhaps not the most elegant solution, but here is what I went with in the end. Any comments or suggestions greatly appreciated. 

 

# -*- coding: utf-8 -*-
import arcpy, os

class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the .pyt file)."""
        self.label = "Toolbox"
        self.alias = ""
        # List of tool classes associated with this toolbox
        self.tools = [Tool]

class Tool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Tool"
        self.description = ""
        self.canRunInBackground = False
    
    currentList = ["CURRENT", "current"]

    def getParameterInfo(self):
        """Define parameter definitions"""
        
        param0 = arcpy.Parameter(displayName="Pro-Document", 
                                 name="proDocument", 
                                 datatype="GPString", 
                                 parameterType="Required", 
                                 direction="Input")
        
        param1 = arcpy.Parameter(displayName="Layout", 
                                 name="inlayout", 
                                 datatype="GPString", 
                                 parameterType="Required", 
                                 direction="Input")
        
        params = [param0, param1]
        
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal 
        validation is performed.  This method is called whenever a 
        parameter has been changed."""
        
        if parameters[0].value:
            p0Val = parameters[0].valueAsText
            if (p0Val.endswith(".aprx") and os.path.exists(p0Val)) or p0Val in self.currentList:
                aprx = arcpy.mp.ArcGISProject(parameters[0].valueAsText)
                layout_list = [l.name for l in aprx.listLayouts()]
                parameters[1].filter.list = layout_list

        return parameters
    
    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool parameter. 
        This method is called after internal validation."""
        
        if parameters[0].value:
            p0Val = parameters[0].valueAsText
            if not ((p0Val.endswith(".aprx") and os.path.exists(p0Val)) or p0Val in self.currentList):
                parameters[0].setErrorMessage("Not a valid ArcPro Document")

        return

    def execute(self, parameters, messages):
        """The source code of the tool."""
        aprx = arcpy.mp.ArcGISProject(parameters[0].valueAsText)
        arpxPath = str(os.path.normpath(aprx.filePath))
        arcpy.AddMessage(f"Pro-Doc Path: {arpxPath}")

        return

 

The main limitation is that the "Pro-Document" input parameter does not have the nifty folder icon (see red arrow) for users to click and navigate to the document. Users have to build/write a path string if not using "current."

Snag_1484366.png

 

 

0 Kudos
Luke_Pinner
MVP Regular Contributor

One suggestion is to use 2 parameters, one a DEFile and the other GPBoolean. Have parameter validation set to clear one when the other is altered. Something like:

 

# -*- coding: utf-8 -*-
import arcpy, os
 
class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the .pyt file)."""
        self.label = "Toolbox"
        self.alias = ""
        # List of tool classes associated with this toolbox
        self.tools = [Tool]
 
class Tool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Tool"
        self.description = ""
        self.canRunInBackground = False
 
    def getParameterInfo(self):
        """Define parameter definitions"""
 
        param0 = arcpy.Parameter(displayName="Current Pro-Document",
                                 name="currentProDocument",
                                 datatype="GPBoolean",
                                 parameterType="Optional",
                                 direction="Input")
 
        param1 = arcpy.Parameter(displayName="Other Pro-Document",
                                 name="otherProDocument",
                                 datatype="DEFile",
                                 parameterType="Optional",
                                 direction="Input")
        param1.filter.list = ['aprx']
 
        param2 = arcpy.Parameter(displayName="Layout",
                                 name="inlayout",
                                datatype="GPString",
                                 parameterType="Required",
                                 direction="Input")
 
        params = [param0, param1, param2]
 
        return params
 
    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True
 
    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a
        parameter has been changed."""
 
        if parameters[1].altered and not parameters[1].hasBeenValidated:
            parameters[0].value = False
            parameters[2].value = None
            parameters[2].filter.list = []
            prodoc = parameters[1].valueAsText
        elif parameters[0].value and parameters[0].altered and not parameters[0].hasBeenValidated:
            parameters[1].value = None
            parameters[2].value = None
            parameters[2].filter.list = []
            prodoc = 'CURRENT'
        else:
            prodoc = None
 
        if prodoc is not None:
            aprx = arcpy.mp.ArcGISProject(prodoc)
            layout_list = [l.name for l in aprx.listLayouts()]
            parameters[2].filter.list = layout_list
 
        return parameters
 
    def execute(self, parameters, messages):
        """The source code of the tool."""
        aprx = arcpy.mp.ArcGISProject(parameters[0].valueAsText)
        arpxPath = str(os.path.normpath(aprx.filePath))
        arcpy.AddMessage(f"Pro-Doc Path: {arpxPath}")
 
        return