Using long GNU style arguments in argparse (don't confuse the extra argument with positional)

For example, with GNU, lsyou can control the coloring with a parameter --color[=WHEN]. Now, in this case, the equal sign is crucial, since it lsmust distinguish between an optional argument --colorand positional arguments (which are lists of files). This is a ls --colorlist of files with colors that matches ls --color=always, but ls --color alwaysdisplays a file always(and colors).

Now from what I saw, argparseit seems to be accepting arguments for long parameters using syntax --longopt <argument>, which will make it impossible to make the argument optional. That is, if I try to implement mylswith the same behavior as GNU ls(this is just an example), I would run into problems, because now it myls --color alwaysmeans the same as myls --color=always(and not as required --colorwithout an argument and alwaysas a positional argument).

I know that I can get around this using myls --color -- always, but there is no way to make this work without this workaround? That is, to argparseindicate that the argument --colormust be provided with syntax --color[=WHEN].

Note that I do not want to rely on the fact that the option --colorhas a finite number of valid arguments. Here is an example of what I tried that did not work properly:

import argparse

parser = argparse.ArgumentParser()

parser.add_argument("--foo",
                    action="store",
                    nargs="?")
parser.add_argument("frob",
                    action="store",
                    nargs=argparse.REMAINDER)

print(parser.parse_args(["alpha", "beta"]))
print(parser.parse_args(["--foo", "alpha", "beta"]))
print(parser.parse_args(["--foo=bar", "alpha", "beta"]))

With an exit:

Namespace(foo=None, frob=['alpha', 'beta'])
Namespace(foo='alpha', frob=['beta'])
Namespace(foo='bar', frob=['alpha', 'beta'])

pay attention to the second, where it is alphainterpreted as an argument --foo. I wanted:

Namespace(foo=None, frob=['alpha', 'beta'])
Namespace(foo=None, frob=['alpha', 'beta'])
Namespace(foo='bar', frob=['alpha', 'beta'])
+4
source share
5 answers

You probably already tried the option ?, and then the required positional:

 p=argparse.ArgumentParser()
 p.add_argument('--foo', nargs='?',default='one', const='two')
 p.add_argument('bar')

which fails with

In [7]: p.parse_args('--foo 1'.split())
usage: ipython3 [-h] [--foo [FOO]] bar
ipython3: error: the following arguments are required: bar

--fooconsumes 1without leaving anything for bar.

http://bugs.python.org/issue9338 . nargs='?' , , . , .

Action, --foo==value, value --foo value, , , . , . , =.

============================

parse_args,

    def consume_optional(....):
        ....
                # error if a double-dash option did not use the
                # explicit argument
                else:
                    msg = _('ignored explicit argument %r')
                    #raise ArgumentError(action, msg % explicit_arg)
                    # change for stack40989413
                    print('Warn ',msg)
                    stop = start_index + 1
                    args = [explicit_arg]
                    action.nargs=None
                    action_tuples.append((action, args, option_string))
                    break

Action:

class MyAction(myparse._StoreConstAction):
    # requies change in consume_optional
    def __call__(self, parser, namespace, values, option_string=None):
        if values:
            setattr(namespace, self.dest, values)
        else:
            setattr(namespace, self.dest, self.const)

:

p = myparse.ArgumentParser()
p.add_argument('--foo', action=MyAction, const='C', default='D')
p.add_argument('bar')

store_const, =explicit_arg, .

, , . .:)

+2

-, . GNU getopt() (man getopt, man 3 getopt). man getopt :

[long] , , "=",

Python getopt, , , :

[ ] .

argparse - , , . , , GNU getopt ls , . , .

+2

:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("files", nargs="*", help="List of files", type=str)
parser.add_argument('--color', dest='color', action='store_true')
parser.add_argument('--color=ALWAYS', dest='color_always', action='store_true')

args = parser.parse_args()
print args

:

[~]$ ./test.py xyz --color
Namespace(color=True, color_always=False, files=['xyz'])
[~]$ ./test.py xyz --color=ALWAYS
Namespace(color=False, color_always=True, files=['xyz'])
+1

! () , , .

, _StoreConstAction , , .

python3 Windows Linux.

import argparse
import inspect

class GnuStyleLongOption(argparse._StoreConstAction):
    def __init__(self, **kw):
        self._real_option_strings = kw['option_strings']
        opts = []
        for option_string in self._real_option_strings:
            opts.append(option_string)
            for choice in kw['choices']:
                opts.append(f'{option_string}={choice}')
        kw['option_strings'] = opts
        self.choices = kw.pop('choices')
        help_choices = [f"'{choice}'" for choice in self.choices]
        kw['help'] += f"; {kw['metavar']} is {', or '.join([', '.join(help_choices[:-1]), help_choices[-1]])}"
        super(GnuStyleLongOption, self).__init__(**kw)

    def __getattribute__(self, attr):
        caller_is_argparse_help = False
        for frame in inspect.stack():
            if frame.function == 'format_help' and frame.filename.endswith('argparse.py'):
                caller_is_argparse_help = True
                break

        if caller_is_argparse_help:
            if attr == 'option_strings':
                return [f'{i}[=WHEN]' for i in self._real_option_strings]
            if attr == 'nargs':
                return 0
            if attr == 'metavar':
                return None

        return super(GnuStyleLongOption, self).__getattribute__(attr)

    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, self.const if '=' not in option_string else option_string[option_string.find('=') + 1:])

p = argparse.ArgumentParser()
p.add_argument('--color', '--colour', action=GnuStyleLongOption, choices=['always', 'never', 'auto'], const='always', default='auto', help='use markers to highlight whatever we want', metavar='WHEN')
p.add_argument('filenames', metavar='filename', nargs='*', help='file to process')
args = p.parse_args()

print(f'color = {args.color}, filenames = {args.filenames}')

:

~ $ ./gnu_argparse.py --help
usage: gnu_argparse.py [-h] [--color[=WHEN]] [filename [filename ...]]

positional arguments:
  filename              file to process

optional arguments:
  -h, --help            show this help message and exit
  --color[=WHEN], --colour[=WHEN]
                        use markers to highlight whatever we want; WHEN is
                        'always', 'never', or 'auto'

~ $ ./gnu_argparse.py
color = auto, filenames = []

~ $ ./gnu_argparse.py file
color = auto, filenames = ['file']

~ $ ./gnu_argparse.py --color file
color = always, filenames = ['file']

~ $ ./gnu_argparse.py --color never file
color = always, filenames = ['never', 'file']

~ $ ./gnu_argparse.py --color=never file
color = never, filenames = ['file']

~ $ ./gnu_argparse.py --colour=always file
color = always, filenames = ['file']
0

nargs .

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--color', nargs='?', const='c', default='d')
>>> parser.parse_args(['XX', '--color', 'always'])
Namespace(bar='XX', color='always')
>>> parser.parse_args(['XX', '--color'])
Namespace(bar='XX', color='c')
>>> parser.parse_args([])
Namespace(bar='d', color='d')

nargs, , , .

By the way, I think it --colorcan use action='store_true'.

parser.add_argument('--color', action='store_true')
-1
source

Source: https://habr.com/ru/post/1662921/


All Articles