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
Date 2021-01-21.00:43:57
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1611189839.05.0.173028976907.issue42973@roundup.psfhosted.org>
In-reply-to
Content
>> Your example is incomplete.  That is _CustomAction?  What namespace does your patch produce.

>> In your example I'd suggest making '--tracks' a nargs=2 and 'append' option.  'choices' would have to be replaced with a either a custom 'type', a custom Action, or post-parsing testing.

My use case and example were oversimplified. The real life use case would be a program that processes multiple sources, with various processing parameters which may change between sources and writes result to destination:

example.py:

#! /usr/bin/python3

import argparse

class _AddSourceAction(argparse.Action):
    def __init__(self, option_strings, dest, nargs=None, const=None,
                 default=None, type=None, choices=None, required=False,
                 help=None, metavar=None):
        super(_AddSourceAction, self).__init__(
            option_strings=option_strings, dest=dest, nargs=nargs,
            const=const, default=default, type=type,
            choices=choices, required=required, help=help,
            metavar=metavar)

    def __call__(self, parser, namespace, values, option_string=None):
        for source in values:
            namespace.sources.append({'name': source,
                'frobnicate': namespace.frobnicate,
                'massage_level': namespace.massage_level})

def process_files(dest, sources):
    for source in sources:
        frob = source["frobnicate"]
        print("processing %s, %sfrobnication, massage level %d " %
              (source["name"],
              "default " if frob is None else "no " if frob == False else "",
              source["massage_level"]))
    print("saving output to %s" % dest)

parser = argparse.ArgumentParser()
if hasattr(parser, "greedy_star"):
    setattr(parser, "greedy_star", True)
parser.add_argument('destination')
parser.add_argument('--frobnicate', action='store_true', dest='frobnicate')
parser.add_argument('--no-frobnicate', action='store_false', dest='frobnicate')
parser.add_argument('--massage-level', type=int, default=5)
parser.add_argument('sources', metavar="source", nargs='*', action=_AddSourceAction)
parser.set_defaults(sources=[])
parser.set_defaults(frobnicate=None)
args = parser.parse_args()

process_files(args.destination, args.sources)

Without patch:

$ ./example.py output.txt --massage-level 4 input1.txt input2.txt --massage-level 5 input3.txt --frobnicate input4.txt input5.txt
example.py: error: unrecognized arguments: input1.txt input2.txt input3.txt input4.txt input5.txt

With patch:

$ PYTHONPATH=patch ./example.py output.txt --massage-level 4 input1.txt input2.txt --massage-level 5 input3.txt --frobnicate input4.txt input5.txt
processing input1.txt, default frobnication, massage level 4
processing input2.txt, default frobnication, massage level 4
processing input3.txt, default frobnication, massage level 5
processing input4.txt, frobnication, massage level 5
processing input5.txt, frobnication, massage level 5
saving output to output.txt

Note that I avoided passing greedy_star to constructor, to avoid error with unpatched argparse. Maybe that should be recommended way to enable this feature? N.b. I don't quite like this name 'greedy_star' seems to informal for me, but I didn't come up with anything better.

In this example frobnicate and massage_level apply to all following sources, but _AddSourceAction could be modified to reset their values, so they would only apply to first following source.

>> It's been a while since I worked on the intermixed patch, but as I recall the OP was happy with the fix.  Also I don't recall any talk about 'matching "optionals" with "positionals" with they relate to. Was that part of the discussion?
>> On Stackoverflow I have seen questions about pairing arguments, and answered some.  I don't recall the best answers.  The tough version is when some of the grouped inputs may be missing 

The use case above seems quite basic and common to me. I'm surprises that I actually didn't find any question on stackoverflow about this exact use case.

>> One question I frequently ask posters who want to parse complex inputs is: 'how are going to explain this to your users?'  'What kind of usage and help do you want see?'

I would (and I will, because I'm really working on a project which will do something like this) put all options which apply to source files into separate option group and add help string to this option group which explains that those options may be specified between source files and that they apply to all (or just first) following source files.

>> Your patch is incomplete, without documentation or tests.

Yeah, I can work on that if there is any chance that this will go anywhere. This is an effort from my side however, because I have quite slow mobile link at this moment. I tried to checkout python sources, but even with -depth 1 it took too long for my patience and I gave up after 'du -sh .git' showed 2G.
History
Date User Action Args
2021-01-21 00:43:59monkeyman79setrecipients: + monkeyman79, r.david.murray, paul.j3
2021-01-21 00:43:59monkeyman79setmessageid: <1611189839.05.0.173028976907.issue42973@roundup.psfhosted.org>
2021-01-21 00:43:59monkeyman79linkissue42973 messages
2021-01-21 00:43:57monkeyman79create