|
msg129714 - (view) |
Author: Wojciech Muła (wm) |
Date: 2011-02-28 16:51 |
Hi, sometimes it is needed to grab variable, but limited, number of options.
For example --point could accept 2, 3 or 4 values: (x,y) or (x,y,z) or
(x,y,z,w). Current version of argparse requires postprocessing:
parser.add_argument('--point', action='append', default=[])
nmps = parser.parse_args()
if not (2 <= len(nmsp.point) <= 4):
raise argparse.ArgumentTypeError("--point expects 2, 3 or 4 values")
I propose to allow pass range of options count to nargs, including
lower/upper bound. For example:
parser.add_argument('--point', nargs=(2,4) ) # from 2 to 4
parser.add_argument('--foo', nargs=(9, None) ) # at least 9
parser.add_argument('--bar', nargs=(None, 7) ) # at most 7
nmsp = parser.parse_args()
I've attached tests and patch made against Python3.2 lib from Debian.
w.
|
|
msg129715 - (view) |
Author: Wojciech Muła (wm) |
Date: 2011-02-28 16:52 |
tests
|
|
msg129755 - (view) |
Author: Daniel Haertle (Danh) |
Date: 2011-03-01 12:57 |
Hi Wojciech,
in your tests, at
def test_add_argument10(self):
"nargs = (0, 1) => optimized to '?'"
opt = self.add_argument(1, None)
self.assertEqual(opt.nargs, argparse.ONE_OR_MORE)
you should change "argparse.ONE_OR_MORE" to "argparse.OPTIONAL".
|
|
msg129917 - (view) |
Author: Wojciech Muła (wm) |
Date: 2011-03-02 20:24 |
Daniel, thanks for note, fixed.
|
|
msg132240 - (view) |
Author: Steven Bethard (bethard) *  |
Date: 2011-03-26 14:07 |
Thanks for the patch. The idea and the approach of the patch look fine. But the patch needs to be against the Python repository:
http://docs.python.org/devguide/patch.html#creating
For the tests, you should integrate your test.py into Lib/test/test_argparse.py.
|
|
msg133537 - (view) |
Author: Wojciech Muła (wm) |
Date: 2011-04-11 17:40 |
Steven, thank you for links, I prepared patch against trunk.
All tests passed.
|
|
msg162475 - (view) |
Author: Alex Frase (atfrase) |
Date: 2012-06-07 16:01 |
I'm new here so I apologize if this is considered poor etiquette, but I'm just commenting to 'bump' this issue. My search for a way to accomplish exactly this functionality led me here, and it seems a patch was offered but no action has been taken on it for over a year now. Alas, it seems I must write a custom Action handler instead.
|
|
msg166171 - (view) |
Author: Steven Bethard (bethard) *  |
Date: 2012-07-22 21:17 |
The tests look like they're testing the right things, but the tests should instead be written like the rest of the argparse tests. For example, look at TestOptionalsNargs3 and TestPositionalsNargs2. You could write your tests to look something like those, e.g.
class TestOptionalsNargs1_3(ParserTestCase):
argument_signatures = [Sig('-x', nargs=(1, 3))]
failures = ['a', '-x', '-x a b c d']
successes = [
('', NS(x=None)),
('-x a', NS(x=['a'])),
('-x a b', NS(x=['a', 'b'])),
('-x a b c', NS(x=['a', 'b', 'c'])),
]
Also, a complete patch will need to document the new feature in the Python documentation, among other things. See the details described here:
http://docs.python.org/devguide/patch.html#preparation
|
|
msg188743 - (view) |
Author: paul j3 (paul.j3) * |
Date: 2013-05-08 22:32 |
Wouldn't it be simpler to use the re {m,n} notation to grab the appropriate number of arguments?
In ArgumentParser _get_nargs_pattern we could add:
+ # n to m arguments, nargs is re like {n,m}
+ elif is_mnrep(nargs):
+ nargs_pattern = '([-A]%s)'%nargs
# all others should be integers
where is_mnrep() tests that the nargs string looks like '{m,n}' (or '{,n}' or '{m,}'). The resulting nargs_pattern will look like
'([-A]{m,n})'
In _format_args() a similar addition would be:
+ elif is_mnrep(action.nargs):
+ result = '%s%s' % (get_metavar(1)[0], action.nargs)
'FOO{2,5}'
It would take more code to generate
FOO FOO [FOO [FOO [FOO]]]
A matching programmer input would be:
parser.add_argument('Foo', nargs='{2,5}')
though it wouldn't be much work to also translate a tuple.
parser.add_argument('Foo', nargs=(2,5))
I'll try to test this implementation against wm's tests.
|
|
msg188757 - (view) |
Author: paul j3 (paul.j3) * |
Date: 2013-05-09 08:01 |
I think this patch should build on http://bugs.python.org/issue9849, which seeks to improve the error checking for nargs. There, add_argument returns an ArgumentError if the nargs value is not a valid string, interger, or it there is mismatch between a tuple metavar and nargs.
This range nargs should be tested at the same time, and return a ArgumentError if possible.
|
|
msg188795 - (view) |
Author: paul j3 (paul.j3) * |
Date: 2013-05-09 23:29 |
This patch adds this `nargs='{m,n}'` or `nargs=(m,n)` feature.
It builds on the `better nargs error message` patch in http://bugs.python.org/msg187754
It includes an argparse.rst paragraph, changes to argparse.py, and additions to test_argparse.py.
The tests include those proposed by wm, rewritten to use the ParserTestCase framework where possible. I did not give a lot of thought to test names. The coverage could also use further thought.
As WM noted some range cases are the equivalent to existing nargs options ('{1,}'=='+'). I did not attempt to code or test such equivalences. Since the '{0,}' form uses regex matching just like '*',
I don't think there is any advantage to making such a translation.
I convert the tuple version (m,n) to the re string '{m,n}' during the add_argument() testing. So it is the string form that is added to the parser action. This is also the format that appears in usage.
The documentation paragraph is:
'{m,n}'. m to n command-line arguments are gathered into a list. This is modeled on the Regular Expression use. '{,n}' gathers up to n arguments. '{m,}' gathers m or more. Thus '{1,}' is the equivalent to '+', and '{,1}' to '?'. A tuple notation is also accepted, '(m,n)', '(None,n)', '(m,None)'. For example:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo', nargs='{2,4}')
>>> parser.parse_args('--foo a b c'.split())
Namespace(foo=['a', 'b', 'c'])
>>> parser.parse_args('--foo a'.split())
usage: PROG [-h] [--foo FOO{2,4}]
PROG: error: argument --foo: expected {2,4} arguments
|
|
| Date |
User |
Action |
Args |
| 2013-05-09 23:29:08 | paul.j3 | set | files:
+ nargsrange.patch
messages:
+ msg188795 |
| 2013-05-09 08:01:33 | paul.j3 | set | messages:
+ msg188757 |
| 2013-05-08 22:32:57 | paul.j3 | set | files:
+ prelimary.patch nosy:
+ paul.j3 messages:
+ msg188743
|
| 2012-07-22 21:17:50 | bethard | set | messages:
+ msg166171 versions:
+ Python 3.4, - Python 3.3 |
| 2012-06-07 16:01:57 | atfrase | set | nosy:
+ atfrase messages:
+ msg162475
|
| 2011-04-11 17:40:23 | wm | set | files:
+ issue11354.patch
messages:
+ msg133537 |
| 2011-03-26 14:07:16 | bethard | set | stage: patch review messages:
+ msg132240 versions:
- Python 3.2 |
| 2011-03-02 21:46:34 | SilentGhost | set | nosy:
+ bethard
|
| 2011-03-02 20:24:25 | wm | set | files:
+ test.py
messages:
+ msg129917 |
| 2011-03-02 20:22:32 | wm | set | files:
- test.py |
| 2011-03-01 12:57:50 | Danh | set | nosy:
+ Danh messages:
+ msg129755
|
| 2011-02-28 16:52:26 | wm | set | files:
+ test.py
messages:
+ msg129715 |
| 2011-02-28 16:51:33 | wm | create | |