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").
Solved! Go to Solution.
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."
Hi,
Why not to specify File as Data Type with .aprx extension? Does it work for you?
BR,
Adam
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.
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']
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.
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."
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