Mailing List Archive

argparse argument post-processing
Hi all,

I have a situation, maybe someone can give some insight.

Say I want to have input which is comma separated array (e.g. paths='path1,path2,path3') and convert it to the desired output - list:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('paths', type=lambda x: list(filter(str.strip, x.split(','))))
So far so good. But this is just an example of what sort of solution I am after.

---------

Now the second case. I want input to be space separated array - bash array. And I want space-separated string returned. My current approach is:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('paths', nargs='+')
args = parser.parse_args()
paths = ' '.join(args.paths)
But what I am looking for is a way to do this, which is intrinsic to `argparse` module. Reason being I have a fair amount of such cases and I don’t want to do post-processing, where post-post-processing happens (after `parser.parse_args()`).

I have tried overloading `parse_args` with post-processor arguments, and that seemed fine, but it stopped working when I had sub-parsers, which are defined in different modules and do not call `parse_args` themselves.

Any ideas appreciated,
Regards,
DG

--
https://mail.python.org/mailman/listinfo/python-list
Re: argparse argument post-processing [ In reply to ]
On Mon, 27 Nov 2023 at 22:31, Dom Grigonis via Python-list
<python-list@python.org> wrote:
>
> Hi all,
>
> I have a situation, maybe someone can give some insight.
>
> Say I want to have input which is comma separated array (e.g. paths='path1,path2,path3') and convert it to the desired output - list:

This is a single argument.

> Now the second case. I want input to be space separated array - bash array. And I want space-separated string returned. My current approach is:
> import argparse
> parser = argparse.ArgumentParser()
> parser.add_argument('paths', nargs='+')
> args = parser.parse_args()
> paths = ' '.join(args.paths)
> But what I am looking for is a way to do this, which is intrinsic to `argparse` module. Reason being I have a fair amount of such cases and I don’t want to do post-processing, where post-post-processing happens (after `parser.parse_args()`).
>

This is parsing multiple arguments.

If you want it space-separated, you can do that, just as a single
argument. Otherwise, what you're doing is taking multiple arguments
and joining them. I'm not sure what you expect to see, but your
examples here pretty clearly show that you are taking multiple
arguments, and joining them with spaces.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: argparse argument post-processing [ In reply to ]
On 11/27/23 04:29, Dom Grigonis via Python-list wrote:
> Hi all,
>
> I have a situation, maybe someone can give some insight.
>
> Say I want to have input which is comma separated array (e.g. paths='path1,path2,path3') and convert it to the desired output - list:
> import argparse
> parser = argparse.ArgumentParser()
> parser.add_argument('paths', type=lambda x: list(filter(str.strip, x.split(','))))
> So far so good. But this is just an example of what sort of solution I am after.

Maybe use "action" rather than "type" here? the conversion of a csv
argument into words seems more like an action.

> Now the second case. I want input to be space separated array - bash array. And I want space-separated string returned. My current approach is:
> import argparse
> parser = argparse.ArgumentParser()
> parser.add_argument('paths', nargs='+')
> args = parser.parse_args()
> paths = ' '.join(args.paths)
> But what I am looking for is a way to do this, which is intrinsic to `argparse` module. Reason being I have a fair amount of such cases and I don’t want to do post-processing, where post-post-processing happens (after `parser.parse_args()`).
>
> I have tried overloading `parse_args` with post-processor arguments, and that seemed fine, but it stopped working when I had sub-parsers, which are defined in different modules and do not call `parse_args` themselves.

Depending on what *else* you need to handle it may or not may work here
to just collect these from the remainders, and then use an action to
join them, like:

import argparse



class JoinAction(argparse.Action):

def __call__(self, parser, namespace, values, option_string=None):

setattr(namespace, self.dest, ' '.join(values))



parser = argparse.ArgumentParser()

parser.add_argument('paths', nargs=argparse.REMAINDER,
action=JoinAction)
args = parser.parse_args()


print(f"{args.paths!r}")







--
https://mail.python.org/mailman/listinfo/python-list
Re: argparse argument post-processing [ In reply to ]
Thank you, exactly what I was looking for!

One more question following this. Is there a way to have a customisable action? I.e. What if I want to join with space in one case and with coma in another. Is there a way to reuse the same action class?

Regards,
DG

> On 27 Nov 2023, at 21:55, Mats Wichmann via Python-list <python-list@python.org> wrote:
>
> On 11/27/23 04:29, Dom Grigonis via Python-list wrote:
>> Hi all,
>> I have a situation, maybe someone can give some insight.
>> Say I want to have input which is comma separated array (e.g. paths='path1,path2,path3') and convert it to the desired output - list:
>> import argparse
>> parser = argparse.ArgumentParser()
>> parser.add_argument('paths', type=lambda x: list(filter(str.strip, x.split(','))))
>> So far so good. But this is just an example of what sort of solution I am after.
>
> Maybe use "action" rather than "type" here? the conversion of a csv argument into words seems more like an action.
>
>> Now the second case. I want input to be space separated array - bash array. And I want space-separated string returned. My current approach is:
>> import argparse
>> parser = argparse.ArgumentParser()
>> parser.add_argument('paths', nargs='+')
>> args = parser.parse_args()
>> paths = ' '.join(args.paths)
>> But what I am looking for is a way to do this, which is intrinsic to `argparse` module. Reason being I have a fair amount of such cases and I don’t want to do post-processing, where post-post-processing happens (after `parser.parse_args()`).
>> I have tried overloading `parse_args` with post-processor arguments, and that seemed fine, but it stopped working when I had sub-parsers, which are defined in different modules and do not call `parse_args` themselves.
>
> Depending on what *else* you need to handle it may or not may work here to just collect these from the remainders, and then use an action to join them, like:
>
> import argparse
>
> class JoinAction(argparse.Action):
> def __call__(self, parser, namespace, values, option_string=None):
> setattr(namespace, self.dest, ' '.join(values))
>
> parser = argparse.ArgumentParser()
> parser.add_argument('paths', nargs=argparse.REMAINDER, action=JoinAction)
> args = parser.parse_args()
>
> print(f"{args.paths!r}")
>
>
>
>
>
>
> --
> https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: argparse argument post-processing [ In reply to ]
On 11/27/23 13:21, Dom Grigonis wrote:
> Thank you, exactly what I was looking for!
>
> One more question following this. Is there a way to have a customisable action? I.e. What if I want to join with space in one case and with coma in another. Is there a way to reuse the same action class?

I've worked more with optparse (the project I work on that uses it has
reasons why it's not feasible to convert to argparse); in optparse you
use a callback function, rather than an action class, and the change to
a callable class is somewhat significant :-; so I'm not really an expert.

The question is how you determine which you want to do - then there's no
problem for the action class's call method to implement it. I presume
you can write an initializer class that takes an extra argument, collect
that and stuff it into an instance variable, then use super to call the
base Action class's initializer with the rest of the args

super().__init__(option_strings=option_strings, *args, **kwargs)

Hopefully someone else has done this kind of thing because now I'm just
guessing!


--
https://mail.python.org/mailman/listinfo/python-list
Re: argparse argument post-processing [ In reply to ]
Yeah, I have been hearing that people are having troubles converting, but I have only used argparse - got lucky there I guess.

I am thinking just making the function which spits the class out. Maybe not very optimised solution, but simple.

Argument parsing in my case is very far from being a bottleneck.

> On 27 Nov 2023, at 22:36, Mats Wichmann <mats@wichmann.us> wrote:
>
> On 11/27/23 13:21, Dom Grigonis wrote:
>> Thank you, exactly what I was looking for!
>> One more question following this. Is there a way to have a customisable action? I.e. What if I want to join with space in one case and with coma in another. Is there a way to reuse the same action class?
>
> I've worked more with optparse (the project I work on that uses it has reasons why it's not feasible to convert to argparse); in optparse you use a callback function, rather than an action class, and the change to a callable class is somewhat significant :-; so I'm not really an expert.
>
> The question is how you determine which you want to do - then there's no problem for the action class's call method to implement it. I presume you can write an initializer class that takes an extra argument, collect that and stuff it into an instance variable, then use super to call the base Action class's initializer with the rest of the args
>
> super().__init__(option_strings=option_strings, *args, **kwargs)
>
> Hopefully someone else has done this kind of thing because now I'm just guessing!
>
>

--
https://mail.python.org/mailman/listinfo/python-list