Question

Being able to validate the list items using choices=servers below is nice.

servers = [ "ApaServer", "BananServer", "GulServer", "SolServer", "RymdServer", "SkeppServer", "HavsServer", "SovServer" ]
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--only', nargs='*', choices=servers, help='Space separated list of case sensitive server names to process')

Is it possible to force an item in the list to be unique, so that no duplicates are allowed?

Was it helpful?

Solution

The way to properly discard duplicates using argparse would be to create your own argparse.Action class that takes care of using set as suggestted by other answers:

import argparse

class UniqueAppendAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        unique_values = set(values)
        setattr(namespace, self.dest, unique_values)

servers = ["ApaServer", "BananServer", "GulServer", "SolServer",
           "RymdServer", "SkeppServer", "HavsServer", "SovServer" ]
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--only', nargs='*', choices=servers, action=UniqueAppendAction,
                    help='Space separated list of case sensitive server names to process')
print parser.parse_args()

Example output:

$ python test.py -o ApaServer ApaServer
Namespace(only=set(['ApaServer']))

OTHER TIPS

I don't think, that you can enforce this with argparse, but I also don't see any reason to do so. Just document in help that duplicates are ignored. If the user passes duplicate arguments to --only, just let her do so, and ignore the duplicate argument when processing the option arguments (e.g. by turing the list into a set() before processing).

Modifying Michel's answer:

In [1]: x = [5,6,5]

In [2]: x_nodups = list(set(x))

In [3]: x_nodups
Out[3]: [5, 6]

In [4]: x_nodups_michel = dict(map(lambda i: (i,1),x)).keys()

In [5]: x_nodups_michel
Out[5]: [5, 6]

Much shorter.

Here's an excerpt from some code that I use for a similar purpose:

def parse_args(argv):
    class SetAction(argparse.Action):
        """argparse.Action subclass to store distinct values"""
        def __call__(self, parser, namespace, values, option_string=None):
            try:
                getattr(namespace,self.dest).update( values )
            except AttributeError:
                setattr(namespace,self.dest,set(values))
    ap = argparse.ArgumentParser(
        description = __doc__,
        formatter_class = argparse.ArgumentDefaultsHelpFormatter,
        )
    ap.add_argument('--genes', '-g',
                    type = lambda v: v.split(','),
                    action = SetAction,
                    help = 'select by specified gene')

This is similar in spirit to jcollado's reply, with a modest improvement: multiple options can be specified, with comma separated values, and they are deduped (via set) across all options.

For example:

snafu$ ./bin/ucsc-bed -g BRCA1,BRCA2,DMD,TNFA,BRCA2 -g BRCA1
Namespace(genes=set([u'BRCA1', u'BRCA2', u'DMD', u'TNFA']))

Note that there are two -g args. BRCA2 is specified twice in the first, but appears only once. BRCA1 is specified in the first and second -g opts, but also appears only once.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top