Analysis arguments that are not declared

I'm writing a utility to run bash commands that essentially take a string and an optional list argument as input, and use the optional arguments to interpolate the string.

I would like it to work like this:

interpolate.py Hello {user_arg} my name is {computer_arg} %% --user_arg=john --computer_arg=hal

      

%%

is a delimiter, it separates the string to be interpolated from the arguments. Following are the arguments used for string interpolation. In this case, the user chose user_arg

and computer_arg

as arguments. The program cannot know in advance which argument names the user will choose.

My problem is how to parse the arguments? I can trivially split the input arguments on a delimiter, but I can't figure out how to get optparse to just provide a list of optional arguments as a dictionary without specifying them beforehand. Does anyone know how to do this without writing a lot of regex?

+3


source to share


3 answers


For something like this, you don't really need optparse or argparse - the benefits of such libraries are of little use in this case (things like single type arguments -v

, invalid parameter checking, validation, etc.)



def partition_list(lst, sep):
    """Slices a list in two, cutting on index matching "sep"

    >>> partition_list(['a', 'b', 'c'], sep='b')
    (['a'], ['c'])
    """
    if sep in lst:
        idx = lst.index(sep)
        return (lst[:idx], lst[idx+1:])
    else:
        return (lst[:], )

def args_to_dict(args):
    """Crudely parses "--blah=123" type arguments into dict like
    {'blah': '123'}
    """
    ret = {}
    for a in args:
        key, _, value = a.partition("=")
        key = key.replace("--", "", 1)
        ret[key] = value

    return ret


if __name__ == '__main__':
    import sys

    # Get stuff before/after the "%%" separator
    string, args = partition_list(sys.argv[1:], "%%")

    # Join input string
    string_joined = " ".join(string)

    # Parse --args=stuff
    d = args_to_dict(args)

    # Do string-interpolation
    print string_joined.format(**d)

      

+1


source


Well, if you use '-' to separate options from arguments instead of %%, optparse / argparse will just give you the arguments as a simple list (treating them as positional arguments instead of toggle arguments). After that, it's not "many" regexes, but just splitting:



for argument in args:
    if not argument.startswith("--"):
        # decide what to do in this case...
        continue
    arg_name, arg_value = argument.split("=", 1)
    arg_name = arg_name[2:]
    # use the argument any way you like

      

+2


source


With argparse, you can use parse_known_args

predefined arguments and any additional arguments. For example using the following script

import sys
import argparse

def main(argv=None):

    parser = argparse.ArgumentParser()

    parser.add_argument('string', type=str, nargs='*',
        help="""String to process. Optionally with interpolation
                (explain this here...)""")

    args, opt_args = parser.parse_known_args(argv)

    print args
    print opt_args

    return 0

if __name__=='__main__':
    sys.exit(main(sys.argv[1:]))

      

and calling with

python script.py Hello, my name is {name} --name=chris

      

outputs the following output:

Namespace(string=['Hello,' 'my', 'name', 'is', '{name}'])
['--name=chris']

      

All that's left to do is skip the namespace args

, which looks for form strings {...}

and replaces them with the corresponding element in opt_args

, if any. (I'm not sure if argparse can automatically use argument interpolation, the example above is the only immediate solution that comes to mind).

+2


source







All Articles