Can you input a parameter value after starting a script tool?

586
11
Jump to solution
10-26-2021 12:25 PM
TigerWoulds
Occasional Contributor III

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? 

0 Kudos
1 Solution

Accepted Solutions
JeffK
by
Regular Contributor

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

 

View solution in original post

11 Replies
JeffK
by
Regular Contributor

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

 

View solution in original post

TigerWoulds
Occasional Contributor III

Thanks I will look into this. Sounds like I will need to use a Python Toolbox over a Script Tool. 

0 Kudos
Luke_Pinner
MVP Regular Contributor

@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.

https://pro.arcgis.com/en/pro-app/latest/arcpy/geoprocessing_and_python/understanding-validation-in-...

0 Kudos
TigerWoulds
Occasional Contributor III

I see. Good to know, thanks!

0 Kudos
TigerWoulds
Occasional Contributor III

@JeffK 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?

TigerWoulds_0-1635365993273.png

# -*- 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

 

0 Kudos
JeffK
by
Regular Contributor

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.

 

0 Kudos
TigerWoulds
Occasional Contributor III

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?

TigerWoulds
Occasional Contributor III

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

 

0 Kudos
Luke_Pinner
MVP Regular Contributor

@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.

0 Kudos