Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Python scripts: handling PF_OPTION and PF_RADIO choices by name
#1
Handling PF_OPTION in scripts is always a bit of a problem when there are many of them or long list of choices. Here is a technique that has several advantages:
  • No choice is ever referenced by its actual integer equivalent.
  • The list of choices can be modified at will (insertions, reorders) without having to hunt the code for changes
  • Choices and their labels cannot be "desynchronized" as would happen with parallel lists
  • Code remains short
All is needed is this small function in the script (it uses the namedtuple from the standard collections module which is in all Python runtimes):

Code:
from collections import namedtuple

def createOptions(name,pairs):
    # namedtuple('FooType',['OPTION1',...,'OPTIONn','labels','labelTuples']
    optsclass=namedtuple(name+'Type',[symbol for symbol,label in pairs]+['labels','labelTuples'])
    # FooType(0,..,n-1,['Option 1',...,'Option N'],[('Option 1',0),...,('Option N',n-1)])
    opts=optsclass(*(
                    range(len(pairs))
                    +[[label for symbol,label in pairs]]
                    +[[(label,i) for i,(symbol,label) in enumerate(pairs)]]
                    ))
    return opts

Then you define your options as a list of  (name,label) tuples, where name is how you refer to that option in the code, and
label is how it appears in the PF_OPTION or PF_RADIO widget:

Code:
[('NONE','None'),('LINKED','Linked layers'),('TEXT','Text layers')]

To create the object that will carry the options, you call the function above, giving it a name, and the list of tuples, and keep the result is a variable:

Code:
MergeOptions=createOptions('Merge',[('NONE','None'),('LINKED','Linked layers'),('TEXT','Text layers')])

The name as passed to the function is not too important, it just needs to be unique among your various set of options. What really counts is the name of the variable in which you keep the object.

In the resulting variable:
  • The name of each tuple in the list is now an attribute: MergeOptions.NONE, MergeOptions.TEXT, MergeOptions.LINKED
  • Thees attributes have the value of their index in the list: MergeOptions.NONE==0, MergeOptions.TEXT==1, MergeOptions.LINKED==2
  • A labels attribute contains the list of labels: MergeOptions.labels==['None','Linked layers','Text layers']
  • A labelTuples attribute contains the list of (labels,value) tuples: MergeOptions.labelsTuples==[('None',0),('Linked layers',1),('Text layers',2)]
Given this, you can define your PF_OPTION like this:

Code:
(PF_OPTION, 'mergeLayers', 'Merge layers',MergeOptions.TEXT,MergeOptions.labels)

or your PF_RADIO like this:

Code:
(PF_RADIO, 'mergeLayers', 'Merge layers',MergeOptions.TEXT,MergeOptions.labelTuples)

To test an option in the code you just use its name:

Code:
if merge==MergeOptions.TEXT:

or even:

Code:
if merge in [MergeOptions.TEXT,MergeOptions.LINKED]:

Happy coding.
Reply


Messages In This Thread
Python scripts: handling PF_OPTION and PF_RADIO choices by name - by Ofnuts - 07-29-2018, 05:44 PM

Forum Jump: