• argparse argument post-processing

    From Dom Grigonis@21:1/5 to All on Mon Nov 27 13:29:01 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Mon Nov 27 23:59:10 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mats Wichmann@21:1/5 to Dom Grigonis via Python-list on Mon Nov 27 12:55:35 2023
    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}")

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mats Wichmann@21:1/5 to Dom Grigonis on Mon Nov 27 13:36:05 2023
    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!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Mon Nov 27 22:42:29 2023
    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!



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Mon Nov 27 22:21:14 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)