Index: Doc/library/optparse.rst =================================================================== --- Doc/library/optparse.rst (revision 77313) +++ Doc/library/optparse.rst (working copy) @@ -403,6 +403,9 @@ ``"append"`` append this option's argument to a list +``"add"`` + add this option's argument to a set + ``"count"`` increment a counter by one @@ -851,6 +854,9 @@ ``"append_const"`` append a constant value to a list + ``"add"`` + add this option's argument to a set + ``"count"`` increment a counter by one @@ -1094,6 +1100,35 @@ ``None``, and an empty list is automatically created the first time the option is encountered. +* ``"add"`` [relevant: :attr:`~Option.type`, :attr:`~Option.dest`, + :attr:`~Option.nargs`] + + The option must be followed by an argument, which is added to the set in + :attr:`~Option.dest`. If no default value for :attr:`~Option.dest` is + supplied, an empty set is automatically created when :mod:`optparse` first + encounters this option on the command-line. If :attr:`~Option.nargs` > 1, + multiple arguments are consumed, and a tuple of length :attr:`~Option.nargs` + is appended to :attr:`~Option.dest`. + + The defaults for :attr:`~Option.type` and :attr:`~Option.dest` are the same as + for the ``"store"`` action. + + Example:: + + parser.add_option("-t", "--tracks", action="add", type="int") + + If ``"-t3"`` is seen on the command-line, :mod:`optparse` does the equivalent + of:: + + options.tracks = set() + options.tracks.add([int("3")]) + + If, a little later on, ``"--tracks=3"`` is seen, it does:: + + options.tracks.add([int("3")]) + + which does not modify the options.tracks set because the value is not unique. + * ``"count"`` [relevant: :attr:`~Option.dest`] Increment the integer stored at :attr:`~Option.dest`. If no default value is Index: Lib/optparse.py =================================================================== --- Lib/optparse.py (revision 77313) +++ Lib/optparse.py (working copy) @@ -488,7 +488,8 @@ "count", "callback", "help", - "version") + "version", + "add") # The set of actions that involve storing a value somewhere; # also listed just for constructor argument validation. (If @@ -499,18 +500,21 @@ "store_false", "append", "append_const", - "count") + "count", + "add") # The set of actions for which it makes sense to supply a value # type, ie. which may consume an argument from the command line. TYPED_ACTIONS = ("store", "append", + "add", "callback") # The set of actions which *require* a value type, ie. that # always consume an argument from the command line. ALWAYS_TYPED_ACTIONS = ("store", - "append") + "append", + "add") # The set of actions which take a 'const' attribute. CONST_ACTIONS = ("store_const", @@ -800,6 +804,8 @@ values.ensure_value(dest, []).append(value) elif action == "append_const": values.ensure_value(dest, []).append(self.const) + elif action == "add": + values.ensure_value(dest, set()).add(value) elif action == "count": setattr(values, dest, values.ensure_value(dest, 0) + 1) elif action == "callback": Index: Lib/test/test_optparse.py =================================================================== --- Lib/test/test_optparse.py (revision 77313) +++ Lib/test/test_optparse.py (working copy) @@ -890,6 +890,23 @@ self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"], {'verbose': 1}, []) +class TestAdd(BaseTest): + def setUp(self): + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) + self.parser.add_option("-a", "--add", action="add", dest="add") + + def test_add(self): + self.assertParseOK(["-a", "foo"], + {"add" : set(["foo"])}, []) + + def test_add_different_value(self): + self.assertParseOK(["-a", "foo", "-add", "bar"], + {"add" : set(["foo", "bar"])}, []) + + def test_add_same_value(self): + self.assertParseOK(["-a", "foo", "--add", "foo"], + {"add" : set(["foo"])}, []) + class TestMultipleArgs(BaseTest): def setUp(self): self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) @@ -944,6 +961,29 @@ {'point': None, 'foo':[(0, 0), (3, 4), (0, 0)]}, []) +class TestMultipleArgsAdd(BaseTest): + def setUp(self): + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) + self.parser.add_option("-f", "--foo", action="add", nargs=2, + type="int", dest="foo") + + def test_nargs_add(self): + self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"], + {'foo': set([(4, -3), (1, 666)])}, + ["blah"]) + + def test_nargs_add_required_values(self): + self.assertParseFail(["-f4,3"], + "-f option requires 2 arguments") + + def test_nargs_add_simple(self): + self.assertParseOK(["--foo=3", "4"], + {'foo':set([(3, 4)])}, []) + + def test_nargs_add_same(self): + self.assertParseOK(["--foo", "3", "4", "-f", "3", "4"], + {'foo':set([(3, 4)])}, []) + class TestVersion(BaseTest): def test_version(self): self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,