1

I am writing a program that should take multiple files as input, where for each file a list of arguments is given. The call could look like:

python myprog.py  \
--file picture1.svg --scale 3 --color false \
--file picture2.svg --scale 1 --color false \
--file pictureX.svg --scale 11 --color true \
-o output.svg

In my case the order of the files matters as well as the correct grouping of the arguments, of course. So I expect finally to receive a dictionary

[["file":"picture1.svg", "scale":3, "color":"false"],
["file":"picture2.svg", "scale":1, "color":"false"],
["file":"pictureX.svg", "scale":11, "color":"true"]]

---------------------------------------//------------------------------

What I found so far is to:

  1. use action="append" using argparse.
import argparse
    parser = argparse.ArgumentParser(description='Call file list with parameters')
    parser.add_argument('-f', '--file', type=str, nargs='+', action='append',  help='file list')
    parser.add_argument('-o', '--output', type=str,  help='output file')
    args = parser.parse_args()
    print(args)

The call would look like:

python myprog.py  \
--file picture1.svg scale:3 color:false \
--file picture2.svg scale:1 color:false \
--file pictureX.svg scale:11 color:true \
-o output.svg

This will give me a list of three lists that I can theoretically parse

[["picture1.svg", "scale:3", "color:false"],
["picture2.svg", "scale:1", "color:false"],
["picturex.svg", "scale:11", "color:true"]]

This would not work optimally for automatic help generation at argparse, will not allow to declare default values, etc. Otherwise seems for me the most optimal solution

  1. The other way would be to generate lists of parameters like
parser.add_argument('-c', '--color', type=str, nargs='+', action='append',  help='color list')
parser.add_argument('-s', '--scale', type=int, nargs='+', action='append', help='scale list')

which would be called like:

python myprog.py  \
--file picture1.svg --scale 3 --color false \
--file picture2.svg --scale 1 --color false \
--file pictureX.svg --scale 11 --color true \
-o output.svg

resulting in list of lists:

[["picture1.svg", "picture2.svg", "picturex.svg"],
["scale:3", "scale:1", "scale:11"],
["color:false","color:false", "color:true"]]

The advantage is in handling everything by argparse. However, if some parameters (for example the second score) are missing, the correspondence between the parameters can not be ensured.

  1. The final possibility I see is to use json as input. It can be easily parsed into the object we want. However, all the advantages of the command line parser will disappear.

What do you think would be the optimal solution, one of the above, or did I overlook something and there is another elegant way to do this? Thank you!

Sergej Zr
  • 11
  • 3

1 Answers1

0

Well, I think I found a way it is supposed to be by argparse.

We can have our own datatypes as command line arguments. So referring to the problem above, we can create a class, somthing like:

class Filetype():
    patterns = {
        'filename': re.compile(".*\.svg"),
        'scale': re.compile("scale:(\d+\.*\d*)"),
        'color': re.compile("color:(True|False)+"),
    }

    def __call__(self, value):
        a = self.patterns["filename"].match(value)
        if a:
            return {"file": value}

        a=self.patterns["scale"].match(value)
        if a:            
            return {"scale": a.group(1)}

        a=self.patterns["color"].match(value)
        if a:
            return {"color": a.group(1)}



        raise argparse.ArgumentTypeError(
                "'{}' should be either: (1) a file name (*.svg), (2) 'scale:FLOAT' parameter, or (3) 'code:[True|False]'".format(
                    value))
        return value

Now, let us add an argument to the parser. The "type" paramter does the work

 parser.add_argument('-f', '--file', type=Filetype(), nargs='+', action='append',
                        help='list of file names with parameters')

we can call our program now with:

python myprog.py  \
--file picture1.svg scale:3 color:false \
--file picture2.svg scale:1 color:false \
--file pictureX.svg scale:11 color:true \
-o output.svg

This seems to be a better compromise. Though we have to perform even simple checks ourself, we can still produce a meaningful error message and argparse still does the heavy work for us

Sergej Zr
  • 11
  • 3