Export to GitHub

argparse - issue #2

Enhanced boolean type and configure-style options


Posted on Mar 27, 2009 by Grumpy Rabbit

[Originally submitted by ndbecker2@gmail.com to the python-hosting.org tracker]

2 things I'd like to see:

  • --option=True/False/1/0 to set the value of a boolean option
  • automatically add --no-option to set the value to false

Comment #1

Posted on Mar 28, 2009 by Grumpy Rabbit

(No comment was entered for this change.)

Comment #2

Posted on Mar 28, 2009 by Grumpy Rabbit

(No comment was entered for this change.)

Comment #3

Posted on Mar 28, 2009 by Grumpy Rabbit

I haven't yet decided whether this deserves to be added as part of argparse or just as a recipe somewhere. For reference though, here is some code that achieves this::

def boolean(string): string = string.lower() if string in ['0', 'f', 'false', 'no', 'off']: return False elif string in ['1', 't', 'true', 'yes', 'on']: return True else: raise ValueError()

class ConfigureAction(argparse.Action): def init(self, option_strings, dest, required=False, help=None, metavar=None): strings = [] self.positive_strings = set() self.negative_strings = set() for string in option_strings: assert string.startswith('--enable') or string.startswith('--with') strings.append(string) self.positive_strings.add(string) neg_string = string.replace('--enable', '--disable') neg_string = neg_string.replace('--with', '--without') strings.append(neg_string) self.negative_strings.add(neg_string) super(ConfigureAction, self).init( option_strings=strings, dest=dest, nargs='?', const=None, default=None, type=boolean, choices=None, required=required, help=help, metavar=metavar) def call(self, parser, namespace, value, option_string=None): if value is None: value = option_string in self.positive_strings elif option_string in self.negative_strings: value = not value setattr(namespace, self.dest, value)

Comment #4

Posted on Mar 30, 2009 by Swift Bear

How is this used?

Comment #5

Posted on Mar 30, 2009 by Grumpy Rabbit

parser = argparse.ArgumentParser() parser.add_argument('--with-fun', action=ConfigureAction) parser.parse_args(['--with-fun']) Namespace(with_fun=True) parser.parse_args(['--without-fun']) Namespace(with_fun=False)

Comment #6

Posted on Jun 24, 2009 by Grumpy Rabbit

import argparse import re

def boolean(string): string = string.lower() if string in ['0', 'f', 'false', 'no', 'off']: return False elif string in ['1', 't', 'true', 'yes', 'on']: return True else: raise ValueError()

class ConfigureAction(argparse.Action):

def __init__(self,
             option_strings,
             dest,
             default=None,
             required=False,
             help=None,
             metavar=None,
             positive_prefixes=['--', '--with-', '--enable-'],
             negative_prefixes=['--no-', '--without-', '--disable-']):
    strings = []
    self.positive_strings = set()
    self.negative_strings = set()
    for string in option_strings:
        assert re.match(r'--[A-z]+', string)
        suffix = string[2:]
        for positive_prefix in positive_prefixes:
            self.positive_strings.add(positive_prefix + suffix)
            strings.append(positive_prefix + suffix)
        for negative_prefix in negative_prefixes:
            self.negative_strings.add(negative_prefix + suffix)
            strings.append(negative_prefix + suffix)
    super(ConfigureAction, self).__init__(
        option_strings=strings,
        dest=dest,
        nargs='?',
        const=None,
        default=default,
        type=boolean,
        choices=None,
        required=required,
        help=help,
        metavar=metavar)

def __call__(self, parser, namespace, value, option_string=None):
    if value is None:
        value = option_string in self.positive_strings
    elif option_string in self.negative_strings:
        value = not value
    setattr(namespace, self.dest, value)

if name == 'main': parser = argparse.ArgumentParser() parser.add_argument('--fun', action=ConfigureAction) assert parser.parse_args([]).fun == None assert parser.parse_args(['--fun']).fun == True assert parser.parse_args(['--with-fun']).fun == True assert parser.parse_args(['--enable-fun']).fun == True assert parser.parse_args(['--no-fun']).fun == False assert parser.parse_args(['--without-fun']).fun == False assert parser.parse_args(['--disable-fun']).fun == False print parser.parse_args()

Comment #7

Posted on Jul 14, 2009 by Swift Bear

Isn't that regex too restictive? assert re.match(r'--[A-z]+', string) How about [0-9]? How about '-_'?

Comment #8

Posted on Jul 21, 2009 by Grumpy Rabbit

Yeah, probably checking for r'--\w' would be fine. Unless you were suggesting that it's valid to have a configure switch like -----foo?

Comment #9

Posted on Jul 21, 2009 by Swift Bear

No, I was thinking of --with-some-function

Comment #10

Posted on Jul 21, 2009 by Grumpy Rabbit

That would have worked already - re.match is just checking the start of the string, and --with-some-function begins with --[A-z].

Comment #11

Posted on Oct 8, 2009 by Swift Bear

Any way to make it interoperate with short options also?

parser.add_argument ('-l', '--limit', action=ConfigureAction, default=True) Traceback (most recent call last): File "test_agc.py", line 23, in parser.add_argument ('-l', '--limit', action=ConfigureAction, default=True) File "/usr/lib/python2.6/site-packages/argparse-1.0.1-py2.6.egg/argparse.py", line 1264, in add_argument action = action_class(**kwargs) File "/home/nbecker/scma-ldpc-fixed-scram-bpsk/test/argparse_bool.py", line 30, in init assert re.match(r'--[A-z]+', string) AssertionError

Comment #12

Posted on Oct 8, 2009 by Grumpy Rabbit

What behavior do you want from short options? Should that add "--no-l", etc.? Or what?

Comment #13

Posted on May 24, 2010 by Grumpy Rabbit

Moved to Python issue tracker: http://bugs.python.org/issue8537

Status: Duplicate

Labels:
Type-Enhancement Priority-Medium