Question: What is the intended / official way of accessing possible arguments from an existing argparse.ArgumentParser
object?
Example: Let's assume the following context:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', '-f', type=str)
Here I'd like to get the following list of allowed arguments:
['-h', '--foo', '--help', '-f']
I found the following workaround which does the trick for me
parser._option_string_actions.keys()
But I'm not happy with it, as it involves accessing a _
-member that is not officially documented. Whats the correct alternative for this task?
First a note on the
argparse
docs - it's basically a how-to-use document, not a formal API. The standard for whatargparse
does is the code itself, the unit tests (test/test_argparse.py
), and a paralyzing concern for backward compatibility.There's no 'official' way of accessing
allowed arguments
, because users usually don't need to know that (other than reading thehelp/usage
).But let me illustrate with a simple parser in an iteractive session:
add_argument
returns the Action object that it created. This isn't documented, but obvious to any one who has created a parser interactively.The
parser
object has arepr
method, that displays major parameters. But it has many more attributes, which you can see withvars(parser)
, orparser.<tab>
in Ipython.The Actions too have
repr
; the Action subclass is determined by theaction
parameter.vars(a)
etc can be used to see all attributes.A key
parser
attribute is_actions
, a list of all defined Actions. This is the basis for all parsing. Note it includes thehelp
action that was created automatically. Look atoption_strings
; that determines whether the Action is positional or optional._option_string_actions
is a dictionary, mapping fromoption_strings
to Actions (the same objects that appear in_actions
). References to those Action objects appear all over the place inargparse
code.Note that there is a key for each
-
string, long or short; but there's nothing forpos
, the positional has an emptyoption_strings
parameter.If that list of keys is what you want, use it, and don't worry about the
_
. It does not have a 'public' alias.I can understand parsing the
help
to discover the same; but that's a lot of work to just avoid using a 'private' attribute. If you worry about the undocumented attribute being changed, you should also worry about the help format being changed. That isn't part of the docs either.help
layout is controlled byparser.format_help
. Theusage
is created from information inself._actions
. Help lines from information in(you don't want to get into
action groups
do you?).There is another way of getting the
option_strings
- collect them from the_actions
:===================
Delving in to code details a bit:
parser.add_argument
creates an Action, and then passes it toparser._add_action
. This is the method the populates both.actions
andaction.option_strings
.I don't think there is a "better" way to achieve what you want.
If you really don't want to use the
_option_string_actions
attribute, you could process theparser.format_usage()
to retrieve the options, but doing this, you will get only the short options names.If you want both short and long options names, you could process the
parser.format_help()
instead.This process can be done with a very simple regular expression:
-+\w+
Or you could first make a dictionnary which contains the argument parser configuration and then build the argmuent parser from it. Such a dictionnary could have the option names as key and the option configuration as value. Doing this, you can access the options list via the dictionnary keys flattened with itertools.chain:
This last way is what I would do, if I was reluctant to use
_option_string_actions
.I have to agree with Tryph's answer.
Not pretty, but you can retrieve them from
parser.format_help()
:There's probably a regular expressions alternative to the above mess...
This started as a joke answer, but I've learned something since - so I'll post it.
Assume, we know the maximum length of an option allowed. Here is a nice answer to the question in this situation:
Of course this is very pedantic as the question doesn't require any specific runtime. So I'll ignore that here. I'll also disregard, that the above version produces a mess of output because one can get rid of it easily.
But more importantly, this method detected the following interesting
argparse
"features":argparse
would also allow--fo
. This has to be a bug.argparse
would also allow-fo
(ie. settingfoo
too
without space or anything). This is documented and intended, but I didn't know it.Because of this, a correct solution is a bit longer and would look something like this (only
parsable
changes, I'll omit the other methods):Summary: Besides all the restrictions (runtime and fixed maximum option length), this is the only answer that correctly respects the real
parser
behavior - however buggy it may even be. So here you are, a perfect answer that is absolutely useless.