I have a python script that will edit all map service capabilities for all services on a federated GIS Server. The script will print out a list of GIS Servers in a federated Enterprise environment > prompt the user to input an integer associated with the index of which GIS Server they want to operate on > all map services are updated on that server.
I am trying to convert this to a script tool in ArcGIS Pro. My script requires the user to input a value after it prints the list of GIS Servers, so it knows which server to run the remaining script on. Is this possible using a script tool? If so, how can I do this?
Solved! Go to Solution.
You can probably have the tool provide a list of available servers using the ToolValidator class as a filter that the person can then select. You can probably handle the index'ing (if needed) in the code behind by setting the selected server's index from the list into another parameter and retrieve it in your script... or just use the server name?
def updateParameters(self):
# """Modify the values and properties of parameters before internal
# validation is performed. This method is called whenever a parameter
# has been changed."""
if self.params[0].value: # conditional to trigger setting the filter
fcFilter = self.params[1].filter # the parameter that the user will pick from
# your code for getting the list of servers
serverList = list(set([line.strip().split('.')[1] for line in serverstuff]))
serverList.sort() # if you want to
fcFilter.list = serverList
return
You can probably have the tool provide a list of available servers using the ToolValidator class as a filter that the person can then select. You can probably handle the index'ing (if needed) in the code behind by setting the selected server's index from the list into another parameter and retrieve it in your script... or just use the server name?
def updateParameters(self):
# """Modify the values and properties of parameters before internal
# validation is performed. This method is called whenever a parameter
# has been changed."""
if self.params[0].value: # conditional to trigger setting the filter
fcFilter = self.params[1].filter # the parameter that the user will pick from
# your code for getting the list of servers
serverList = list(set([line.strip().split('.')[1] for line in serverstuff]))
serverList.sort() # if you want to
fcFilter.list = serverList
return
Thanks I will look into this. Sounds like I will need to use a Python Toolbox over a Script Tool.
@tigerwoulds wrote:Sounds like I will need to use a Python Toolbox over a Script Tool.
No you can still use a script tool. They support validation code.
I see. Good to know, thanks!
@Anonymous User I'm attempting a python toolbox for the first time and hitting a wall. I would like the enter the Portal URL, username, password and have the GIS Server parameter auto populate with a drop down list of all my federated servers. If I comment out the updateParameters method, then I can enter the other parameters without the error. Any ideas what I need to do here?
# -*- coding: utf-8 -*-
import arcpy
from arcgis.gis import GIS
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 = "toolbox"
# List of tool classes associated with this toolbox
self.tools = [SwitchInstanceTypeToDedicated]
class SwitchInstanceTypeToDedicated(object):
def __init__(self):
"""Define the tool (tool name is the name of the class)."""
self.label = "Edit REST Service"
self.description = ""
self.canRunInBackground = False
def getParameterInfo(self):
"""Define parameter definitions"""
param0 = arcpy.Parameter(
displayName="Portal URL eg. https://arcgis.com/portal",
name="PortalURL",
datatype="string",
parameterType="Required",
direction="Input")
param1 = arcpy.Parameter(
displayName="Username (must be Admin level)",
name="username",
datatype="string",
parameterType="Required",
direction="Input")
param2 = arcpy.Parameter(
displayName="Password",
name="password",
datatype="string",
parameterType="Required",
direction="Input")
param3 = arcpy.Parameter(
displayName="GIS Server",
name="gisSrv",
datatype="string",
parameterType="Required",
direction="Input")
params = [param0, param1, param2, param3]
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 params[0].value: # conditional to trigger setting the filter
fcFilter = params[3].filter # the parameter that the user will pick from
# your code for getting the list of servers
# Connect to GIS Portal
gis = GIS(param0, param1, param2, verify_cert=False)
# List GIS Servers
serverList = gis.admin.servers.list()
# serverList.sort() # if you want to
fcFilter.list = serverList
return
def updateMessages(self, parameters):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
return
def execute(self, parameters, messages):
"""The source code of the tool."""
arcpy.AddMessage('Hello World')
return
Couple of things here that I would try- I think you need to set the param0-param3 to be instance variables by adding the 'self.' in front of them. Class variables (without the self.) can only be assigned when a class has been defined. Instance variables (self.) , on the other hand, can be assigned or changed at any time. Then you can access them/change them in your other class methods by also referring to them with the 'self.' prefix. You also need to get the values of the parameters, instead of passing the complete param object so adding .valueAsText() on the end of them should get you the string value.
Thanks! After some tinkering, I've got it working. I can enter my portal url, user, password and I get a list of GIS Servers to choose for the 3rd parameter.
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."""
# Create a dropdown list for the GIS Server Parameter of all federated GIS Servers
portal = parameters[0].valueAsText
user = parameters[1].valueAsText
password = parameters[2].valueAsText
if parameters[2].value: # If the password field is filled in
gis = GIS(portal, user, password, verify_cert=False)
serverList = gis.admin.servers.list()
newList = []
for item in serverList:
myString = str(item)
newList.append(myString)
parameters[3].filter.list = newList
One issue is I am using the ArcGIS Python API in line 11 to get a List of GIS Server. If I pass that list directly into my Filter List my toolbox throws this error.
ValueError: FilterObject: illegal list value
Turns out I need to convert each item in my serverList to a string and add it to a new list. Then, using the new list, my toolbox dropdown works correctly.
Say the user selects the 2 item in the dropdown (index 1), how I store that index number as a variable in my updateParameters function and use that in my execute function later?
This is what I've tried so far, but I need to be able to use the variable 'b' in my execute function. Any ideas?
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."""
# Create a dropdown list for the GIS Server Parameter of all federated GIS Servers
portal = parameters[0].valueAsText
user = parameters[1].valueAsText
password = parameters[2].valueAsText
if parameters[2].value: # If the password field is filled in
gis = GIS(portal, user, password, verify_cert=False)
serverList = gis.admin.servers.list()
newList = []
for item in serverList:
myString = str(item)
newList.append(myString)
parameters[3].filter.list = newList
if parameters[3] in newList:
b = newList.index(parameters[3])
return
@tigerwoulds wrote:This is what I've tried so far, but I need to be able to use the variable 'b' in my execute function.
You don't. You just use parameters[3].valueAsText in your execute function.