Vicky Nguyen
Vicky Nguyen

Reputation: 35

Find the order of arguments in argparse python3

I have this code

parser = argparse.ArgumentParser()
parser.add_argument('--input')
parser.add_argument('--min')
parser.add_argument('--max')
args = parser.parse_args()

How can I know the order of arguments ? For example, if I type:

python somefile.py --min min --input file.csv

How can I know position of --min is before --input and user didn't type --max?

Upvotes: 2

Views: 1175

Answers (2)

hpaulj
hpaulj

Reputation: 231355

By design argparse is supposed to handle the optionals in any order. They are parsed in the order that they are provided in the command line, but it does not keep any record of that order. positionals without a keyword are handled in the order that they are defined by the add_argument definitions.

All attributes are added to the args Namespace with their defaults at the start of parsing. And it does this in the add_argument order. In newer Pythons this order is preserved in the args.__dict__ (which vars(args) also shows).

But in print(args), the attributes are displayed in sorted order. usage also preserves the definition order for optionals.

So for a sample parser:

In [11]: p.print_usage()                                                        
usage: ipython3 [-h] [--foo FOO] [--test TEST] [--aaa AAA] bar

In [12]: args=p.parse_args(['xxx'])  

In [13]: args                                                                   
Out[13]: Namespace(aaa=None, bar='xxx', foo=None, test=None)  # sorted

In [14]: vars(args)                                                             
Out[14]: {'foo': None, 'bar': 'xxx', 'test': None, 'aaa': None} # definition

In [15]: [a.dest for a in p._actions]                                           
Out[15]: ['help', 'foo', 'bar', 'test', 'aaa']  # definition order

So recording the order of occurrence of the arguments in the command line is, with just argparse, awkward. In a sense it goes against the spirit of optionals.

Alternatives:

  • work directly with the sys.argv

  • customize the action class

  • customize the Namespace class


One other trick comes to mind:

If the default is argparse.SUPPRESS, the default is not added to args. Then I think the var(args) order will be the order in which values are parsed and added.

In [16]: for a in p._actions: a.default=argparse.SUPPRESS  
In [24]: args=p.parse_args(['--test', 'ttt','xxx','--foo=3'])                   
In [25]: args                                                                   
Out[25]: Namespace(bar='xxx', foo='3', test='ttt')
In [26]: vars(args)                                                             
Out[26]: {'test': 'ttt', 'bar': 'xxx', 'foo': '3'}

Users may repeat optionals, with repeats over writing previous values.

Upvotes: 1

RafalS
RafalS

Reputation: 6324

I think it might be tricky to obtain that information from parser itself, but it can be easily obtained from sys.argv:

def get_arg_index(args: list, name: str):
    return next((i for i, v in enumerate(args) if v.startswith(name)), None)


print(get_arg_index(sys.argv, "--min"))
print(get_arg_index(sys.argv, "--max"))

Upvotes: 3

Related Questions