meylor / argparse

Automatically exported from code.google.com/p/argparse
Other
0 stars 0 forks source link

Enhanced boolean type and configure-style options #2

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
[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

Original issue reported on code.google.com by steven.b...@gmail.com on 27 Mar 2009 at 5:06

GoogleCodeExporter commented 9 years ago

Original comment by steven.b...@gmail.com on 28 Mar 2009 at 2:03

GoogleCodeExporter commented 9 years ago

Original comment by steven.b...@gmail.com on 28 Mar 2009 at 2:05

GoogleCodeExporter commented 9 years ago
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)

Original comment by steven.b...@gmail.com on 28 Mar 2009 at 10:18

GoogleCodeExporter commented 9 years ago
How is this used?

Original comment by ndbeck...@gmail.com on 30 Mar 2009 at 11:08

GoogleCodeExporter commented 9 years ago
>>> 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)

Original comment by steven.b...@gmail.com on 30 Mar 2009 at 2:35

GoogleCodeExporter commented 9 years ago
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()

Original comment by steven.b...@gmail.com on 24 Jun 2009 at 12:47

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

Original comment by ndbeck...@gmail.com on 14 Jul 2009 at 12:24

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

Original comment by steven.b...@gmail.com on 21 Jul 2009 at 2:47

GoogleCodeExporter commented 9 years ago
No, I was thinking of --with-some-function

Original comment by ndbeck...@gmail.com on 21 Jul 2009 at 10:55

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

Original comment by steven.b...@gmail.com on 21 Jul 2009 at 12:10

GoogleCodeExporter commented 9 years ago
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 <module>
    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

Original comment by ndbeck...@gmail.com on 8 Oct 2009 at 12:31

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

Original comment by steven.b...@gmail.com on 8 Oct 2009 at 4:42

GoogleCodeExporter commented 9 years ago
Moved to Python issue tracker: http://bugs.python.org/issue8537

Original comment by steven.b...@gmail.com on 24 May 2010 at 2:58