In the validation class for a script tool, I want to set the list for a multi-value string parameter by explicitly creating the order of items in a list. For example:
self.params["objects"].filter.list = ["bananas", "strawberries", "limes", "apples"]
But the values get sorted alphabetically:
Can I stop the parameter from sorting the values?
Solved! Go to Solution.
That's odd.
(I'm on 3.3, for reference. Named parameter support was added in 3.2)
This points out a weird difference between an ATBX and a PYT.
For a PYT, setting a multivalue string parameter will give you this:
param1 = arcpy.Parameter(displayName=("EGDB Sources:\n"
"Old EGDB SDE file"),
name="EGDB_CROSS",
datatype="GPString",
parameterType="Optional",
multiValue = True,
direction="Input")
param1.filter.list = ["banana", "apple", "lemon", "kiwi"]
However, in an ATBX, you get this:
Interestingly enough, the dropdown is in the correct order, but the "add multiple" is not.
Honestly, I recommend writing in a Python Toolbox anyway. It's a little bit different at the very beginning, but it gives you a lot more control over your stuff, and apparently the implementation of various parameter types in the UI is different.
Try.
self.params[1].filter.list = valueList
self.params[1].values = self.params[1].filter.list
self.params["objects"].values
That's odd.
(I'm on 3.3, for reference. Named parameter support was added in 3.2)
This points out a weird difference between an ATBX and a PYT.
For a PYT, setting a multivalue string parameter will give you this:
param1 = arcpy.Parameter(displayName=("EGDB Sources:\n"
"Old EGDB SDE file"),
name="EGDB_CROSS",
datatype="GPString",
parameterType="Optional",
multiValue = True,
direction="Input")
param1.filter.list = ["banana", "apple", "lemon", "kiwi"]
However, in an ATBX, you get this:
Interestingly enough, the dropdown is in the correct order, but the "add multiple" is not.
Honestly, I recommend writing in a Python Toolbox anyway. It's a little bit different at the very beginning, but it gives you a lot more control over your stuff, and apparently the implementation of various parameter types in the UI is different.
It does seem like there's some different handling going on with the named parameter system. I usually just throw this into my code library somewhere:
class Parameters(list):
""" Parameters class that replaces the list of parameters in the tool functions
with an object that can be access the parameters by name, index, or attribute.
USAGE
You still need tool functions to return a list of parameters as the parameters list
is rebuilt each time it is passed beteween the tool functions. That list can be immediately
converted to a Parameters object at the beginning of the function.
>>> def execute(self, parameters: list[arcpy.Parameter]) -> None:
>>> parameters = Parameters(parameters)
>>> paramA = parameters.paramA.value
or
>>> paramA = parameters['paramA'].value
or
>>> paramA = parameters[0].value
Assuming that paramA is the first parameter in the list of parameters
"""
def __init__(self, parameters: list[arcpy.Parameter]) -> None:
self.__dict__.update({parameter.name: parameter for parameter in parameters})
return
def __iter__(self) -> Generator[arcpy.Parameter, None, None]:
for value in self.__dict__.values():
yield value
return
def __len__(self) -> int:
return len(self.__dict__)
def __getitem__(self, key) -> arcpy.Parameter:
if isinstance(key, int):
return list(self)[key]
return self.__dict__[key]
def __setitem__(self, key, value) -> None:
if isinstance(key, int):
self.__dict__[list(self.__dict__)[key]] = value
self.__dict__[key] = value
return
def __getattr__(self, name: str) -> arcpy.Parameter:
if name in self.__dict__:
return self.__dict__[name]
return super().__getattribute__(name)
def append(self, parameter: arcpy.Parameter) -> None:
if not isinstance(parameter, arcpy.Parameter):
raise TypeError(f"Parameter must be of type arcpy.Parameter, not {type(parameter)}")
self.__dict__[parameter.name] = parameter
def extend(self, parameters: list[arcpy.Parameter]) -> None:
for parameter in parameters:
self.append(parameter)
def __repr__(self) -> str:
return str(list(self.__dict__.values()))
This gives you the ability to immediately consume the `parameters` list and access it with all possible access options (dot, key, index). It's super hacky, but gives you named parameter control without having to enter the ESRI black box. It's also acting like a mapping even though it inherits list because tool methods expect a list object so passing it a mapping makes it angry.
Since a new list is constructed by the system on each function call you do need to explicitly cast to this class in order to get the benefits.
Thanks.
I think this is the answer: that it can't be controlled. That's too bad, but I can live with it.
Well, something else I was pointed to was this page , which may be helpful to you.