This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author monkeyman79
Recipients monkeyman79, paul.j3, r.david.murray, v+python
Date 2021-01-28.02:09:22
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1611799763.73.0.428342795169.issue42973@roundup.psfhosted.org>
In-reply-to
Content
> So in the big picture, the purpose of this change is to treat the inputs like a kind of state-machine.

Not necessarily that. Simple parsers should be easy to write, complicated parsers should be _possible_ to write. Users should be able to do whatever they wish by providing custom actions. Like writing Conway's Life in Excel or building Turing Machine using bricks and conveyors. Problem with positional parameter is a blocker. Fact that you can: 1. mix positional parameters with options in general, 2. have unlimited number of positional parameters, but 3. can't have 1 and 2 at the same time, makes great number of things impossible. For me that looks like a bug, not a feature.

Capture actions are second priority for me, because if this PR goes through, user will be able to write his own actions.

> While the proposed change to the core parser is (apparently) minor, it does occur at the center of the action. That is not the place we want any (new) bugs or backward incompatibility.

The core change is apparently minor, and also actually minor. It boils out to this:

@@ -2010,17 +2020,23 @@ def consume_positionals(start_index):
             match_partial = self._match_arguments_partial
             selected_pattern = arg_strings_pattern[start_index:]
             arg_counts = match_partial(positionals, selected_pattern)
+            action_index = 0

             # slice off the appropriate arg strings for each Positional
             # and add the Positional and its args to the list
-            for action, arg_count in zip(positionals, arg_counts):
+            for arg_count in arg_counts:
+                action = positionals[action_index]
                 args = arg_strings[start_index: start_index + arg_count]
                 start_index += arg_count
                 take_action(action, args)
+                # if positional action nargs is '**',
+                # never remove it from actions list
+                if action.nargs != AS_MANY_AS_POSSIBLE:
+                    action_index += 1

             # slice off the Positionals that we just parsed and return the
             # index at which the Positionals' string args stopped
-            positionals[:] = positionals[len(arg_counts):]
+            positionals[:] = positionals[action_index:]
             return start_index

It's not hard to determine that if all action.nargs != AS_MANY_AS_POSSIBLE, old and new code do exactly the same.
Besides that's what tests and code review is for. As for backward compatibility, nargs='**' was illegal until now,
and for all parameters with nargs!='**' the code behaves exactly as before.

> And the full implementation requires a new Action subclass that is quite different from existing ones.

No, that's an extra. That's why it's separate issue and separate PR. This issue is about giving users ability to write their own actions.

> Given how different this is from the normal argparse parsing (and the POSIX parsing argparse seeks to emulate), I question the wisdom of adding this, in part or whole, to the stock distribution.  It could certainly be published as a pypi.  That already has a number of  parsers, some built on argparse, others stand alone.
>
> I also wonder whether it would be simpler to do this kind of parsing directly from sys.argv.  Just step through that list, consuming the values and flags in sequence.

In other words, "if argparse doesn't meet your requirements, you can write your own parser". I don't think that's the way to go.

Both GNU getopt and GNU argp_parse allow mixing options with positional arguments without reordering. For getopt it's: options argument string begins with a hyphen, for argp_parse it's ARGP_IN_ORDER flag. I don't see why argparse wouldn't allow that. Original POSIX getopt didn't even have longopts.

> Sorry to sound like a wet blanket, but I've seen too many seemingly innocent patches that caused unforeseen problems down the line.

Yeah, that can be said about any project at any time - changes can introduce bugs, so let's just keep it as it is. I appreciate your ideas, but your criticism does sound unsubstantiated: "POSIX getopts didn't have it", "it can be done on pypi", "enhancements introduce bugs".

I think this change should be applied, because it is small change in code which removes significant obstacle in writing advanced option parsers.
History
Date User Action Args
2021-01-28 02:09:23monkeyman79setrecipients: + monkeyman79, v+python, r.david.murray, paul.j3
2021-01-28 02:09:23monkeyman79setmessageid: <1611799763.73.0.428342795169.issue42973@roundup.psfhosted.org>
2021-01-28 02:09:23monkeyman79linkissue42973 messages
2021-01-28 02:09:22monkeyman79create