Search code examples
pythonargumentsargparse

Processing arguments for subprocesses using argparse: "Expected one argument"


First of all, I am sorry about the title that does not give a perfect idea of what my problem is, I kinda struggled with it, so I am going to illustrate it more clearly with a reproducible example:

I have the following code:

example.py:

import argparse


def parse_args():
    """Command line argument parser

    Returns:
        The extra arguments
    """

    parser = argparse.ArgumentParser(description="Arguments for test runner")
    parser.add_argument('-e', '--extra_args', type=str, default="", help="Extra arguments. Enter as a single line encapsulated by quotes. Example: -e \"--repeat=0 otherstuff -x anotherpositional\"")

    arguments = parser.parse_args()

    return arguments


if __name__ == "__main__":
    args = parse_args()
    print(args.extra_args)

The --extra_args argument is then going to be used as a positional argument for a subprocess call.

The argument I need to pass is the following one: --repeat=0. It does not work, I got the following results:

python example.py -e "toto" # This print toto
python example.py -e "--repeat = 0" # This print --repeat = 0
python example.py -e "--repeat" # error: argument -e/--extra_args: expected one argument
python example.py -e "--repeat=0" # error: argument -e/--extra_args: expected one argument

What I understand is that the parser process the --repeat as an argument, find no value for it, and breaks. But unfortunately I have no choice than to write '--repeat=0' all attached, because of the software receiving it.

Would you know any workaround around it ?


Solution

  • I found an ugly workaround but if it exit, I would enjoy a better solution.

    I added the following function:

    def __workaround_for_extra_utr_args():
        """This workaround is necessary because utr can receives args at \"--repeat=0\" which are not processable by arg parse, even as a string"""
        import sys
    
        index_of_extra_args = [sys.argv.index(v) for v in ['-e', '--extra_utr_args'] if v in sys.argv]
        space = " "
    
        if index_of_extra_args:
            index_of_extra_args = index_of_extra_args[0]
    
            if space not in sys.argv[index_of_extra_args + 1]:
                sys.argv[index_of_extra_args + 1] = sys.argv[index_of_extra_args + 1] + space
    

    Call it before calling the parser, and it will be able to return the string, it is then possible to remove the extra space after the parsing.