Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

argparse: Associate arguments with another argument

With argparse, it's possible to repeat an argument and collect all the values into a list:

parser = ArgumentParser()
parser.add_argument('-o', '--output', action='append')

args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(vars(args))
# {'output': ['output1', 'output2']}

I'm looking for a way to associate flags with each of these arguments, so that it's possible to do this:

args = parser.parse_args(['-o', 'output1', '--format', 'text',
                          '-o', 'output2', '--format', 'csv'])

And get an output like this (or something similar):

{'output': {'output1': {'format': 'text'},
            'output2': {'format': 'csv'}
           }
}

Ideally, these flags should follow the usual semantics - for example, --format could be optional, or there could be multiple arguments associated with each -o output, in which case they should be passable in any order (i.e. -o output1 -a -b -c should be equivalent to -o output1 -c -a -b).

Can this be done with argparse?

like image 951
Aran-Fey Avatar asked Mar 07 '23 01:03

Aran-Fey


1 Answers

3 parsers operating on a general set of -o and -f flags:

Simple append - no connection between the 2 dest:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action='append')
parser.add_argument('-f', '--format', action='append')

args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', '--format', 'text',
                          '-o', 'output2', '--format', 'csv'])
print(args)

args = parser.parse_args(['-o', 'output1',
                          '-o', 'output2', '--format', 'csv',
                          '-o', 'output3', '-f1', '-f2'])
print(args)
print()

nargs='+'; keeps arguments together, but does not use format flags:

parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action='append', nargs='+')
#parser.add_argument('-f', '--format', action='append')

args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', 'text',
                          '-o', 'output2', 'csv'])
print(args)

args = parser.parse_args(['-o', 'output1',
                          '-o', 'output2', 'csv',
                          '-o', 'output3', '1', '2'])
print(args)
print()

Custom classes derived from the append class. Creates a dictionary for each output. format modifies the last output dictionary:

class Foo1(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        items = argparse._copy.copy(argparse._ensure_value(namespace, self.dest, []))
        dd = {'output': values, 'format': []}
        items.append(dd)
        setattr(namespace, self.dest, items)

class Foo2(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        items = argparse._copy.copy(argparse._ensure_value(namespace, self.dest, []))
        last = items[-1]   # error if -f before -o
        last['format'].append(values)
        setattr(namespace, self.dest, items)

parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action=Foo1)
parser.add_argument('-f', '--format', action=Foo2, dest='output')

args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', '--format', 'text',
                          '-o', 'output2', '--format', 'csv'])
print(args)

args = parser.parse_args(['-o', 'output1',
                          '-o', 'output2', '--format', 'csv',
                          '-o', 'output3', '-f1', '-f2'])
print(args)
print()

produces:

1238:~/mypy$ python stack48504770.py 
Namespace(format=None, output=['output1', 'output2'])
Namespace(format=['text', 'csv'], output=['output1', 'output2'])
Namespace(format=['csv', '1', '2'], output=['output1', 'output2', 'output3'])

Namespace(output=[['output1'], ['output2']])
Namespace(output=[['output1', 'text'], ['output2', 'csv']])
Namespace(output=[['output1'], ['output2', 'csv'], ['output3', '1', '2']])

Namespace(output=[{'output': 'output1', 'format': []}, 
                  {'output': 'output2', 'format': []}])
Namespace(output=[{'output': 'output1', 'format': ['text']}, 
                  {'output': 'output2', 'format': ['csv']}])
Namespace(output=[{'output': 'output1', 'format': []}, 
                  {'output': 'output2', 'format': ['csv']}, 
                  {'output': 'output3', 'format': ['1', '2']}])
()
like image 146
hpaulj Avatar answered Mar 20 '23 12:03

hpaulj