Correct way to get allowed arguments from ArgumentParser
<p><strong>Question:</strong> What is the intended / official way of accessing possible arguments from an existing <code>argparse.ArgumentParser</code> object?</p>

<p><strong>Example:</strong> Let's assume the following context:</p>

<pre><code>import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', '-f', type=str)
</code></pre>

<p>Here I'd like to get the following list of allowed arguments:</p>

<pre><code>['-h', '--foo', '--help', '-f']
</code></pre>

<p>I found the following workaround which does the trick for me</p>

<pre><code>parser._option_string_actions.keys()
</code></pre>

<p>But I'm not happy with it, as it involves accessing a <code>_</code>-member that is not officially documented. Whats the correct alternative for this task?</p>

<p>First a note on the <code>argparse</code> docs - it's basically a how-to-use document, not a formal API.  The standard for what <code>argparse</code> does is the code itself, the unit tests (<code>test/test_argparse.py</code>), and a paralyzing concern for backward compatibility.</p>

<p>There's no 'official' way of accessing <code>allowed arguments</code>, because users usually don't need to know that (other than reading the <code>help/usage</code>).</p>

<p>But let me illustrate with a simple parser in an iteractive session:</p>

<pre><code>In [247]: parser=argparse.ArgumentParser()
In [248]: a = parser.add_argument('pos')
In [249]: b = parser.add_argument('-f','--foo')
</code></pre>

<p><code>add_argument</code> returns the Action object that it created.  This isn't documented, but obvious to any one who has created a parser interactively.</p>

<p>The <code>parser</code> object has a <code>repr</code> method, that displays major parameters.  But it has many more attributes, which you can see with <code>vars(parser)</code>, or <code>parser.&lt;tab&gt;</code> in Ipython.</p>

<pre><code>In [250]: parser
Out[250]: ArgumentParser(prog='ipython3', usage=None, description=None, formatter_class=&lt;class 'argparse.HelpFormatter'&gt;, conflict_handler='error', add_help=True)
</code></pre>

<p>The Actions too have <code>repr</code>; the Action subclass is determined by the <code>action</code> parameter.</p>

<pre><code>In [251]: a
Out[251]: _StoreAction(option_strings=[], dest='pos', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [252]: b
Out[252]: _StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
</code></pre>

<p><code>vars(a)</code> etc can be used to see all attributes.</p>

<p>A key <code>parser</code> attribute is <code>_actions</code>, a list of all defined Actions.  This is the basis for all parsing.  Note it includes the <code>help</code> action that was created automatically.  Look at <code>option_strings</code>; that determines whether the Action is positional or optional.</p>

<pre><code>In [253]: parser._actions
Out[253]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=[], dest='pos',....),
 _StoreAction(option_strings=['-f', '--foo'], dest='foo', ...)]
</code></pre>

<p><code>_option_string_actions</code> is a dictionary, mapping from <code>option_strings</code> to Actions (the same objects that appear in <code>_actions</code>).  References to those Action objects appear all over the place in <code>argparse</code> code.</p>

<pre><code>In [255]: parser._option_string_actions
Out[255]: 
{'--foo': _StoreAction(option_strings=['-f', '--foo'],....),
 '--help': _HelpAction(option_strings=['-h', '--help'],...),
 '-f': _StoreAction(option_strings=['-f', '--foo'], dest='foo',...),
 '-h': _HelpAction(option_strings=['-h', '--help'], ....)}

In [256]: list(parser._option_string_actions.keys())
Out[256]: ['-f', '--help', '-h', '--foo']
</code></pre>

<p>Note that there is a key for each <code>-</code> string, long or short; but there's nothing for <code>pos</code>, the positional has an empty <code>option_strings</code> parameter.</p>

<p>If that list of keys is what you want, use it, and don't worry about the <code>_</code>.  It does not have a 'public' alias.</p>

<p>I can understand parsing the <code>help</code> 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.</p>

<p><code>help</code> layout is controlled by <code>parser.format_help</code>.  The <code>usage</code> is created from information in <code>self._actions</code>.  Help lines from information in</p>

<pre><code>    for action_group in self._action_groups:
        formatter.add_arguments(action_group._group_actions)
</code></pre>

<p>(you don't want to get into <code>action groups</code> do you?).</p>

<p>There is another way of getting the <code>option_strings</code> - collect them from the <code>_actions</code>:</p>

<pre><code>In [258]: [a.option_strings for a in parser._actions]
Out[258]: [['-h', '--help'], [], ['-f', '--foo']]
</code></pre>

<p>===================</p>

<p>Delving in to code details a bit:</p>

<p><code>parser.add_argument</code> creates an Action, and then passes it to <code>parser._add_action</code>.  This is the method the populates both <code>.actions</code> and  <code>action.option_strings</code>.</p>

<pre><code>    self._actions.append(action)
    for option_string in action.option_strings:
        self._option_string_actions[option_string] = action
</code></pre>

python argparse