0

Python novice here. I am attempting to set up an argument in argparse that takes the form of "-x option=value -x option2=value..."

I'm using the following which passes the arguments.

swlist_parser.add_argument("-x", nargs="+",action='append',metavar='option',
              help="-x option=value, set the option to value")

I have a dictionary of default arguments that are available for the command. I want to use -x option=value to modify the dictionary of default arguments with the one on the command line.

swlist -x distribution_target_directory=/tmp -x admin_directory=/var/lib/sw -x another_option=another_value ...

# Code I have
# args.x is now the following:
   if args.x != None:
       print("-x options passed: ")
       cliopts = {}
       for opt in (args.x):
           print(opt)
   

-x options passed:

['distribution_target_directory=/tmp']
['admin_directory=/var']

The arguments to -x are now class 'list'. I need a solution to add these to a dictionary.

I tried modifying the argparse to be dictionary. This option doesn't allow for the option=value

swlist_parser.add_argument("-x", nargs="+",action='append',type=dict,metavar='option', help="-x option=value, set the option to value")
swlist.py  -x distribution_target_directory=/tmp -x admin_directory=/var  -X /home/pweber/pauls.defaults

usage: swlist [options] [software_selections] [@ target_selections]
swlist: error: argument -x: invalid dict value: 'distribution_target_directory=/tmp'

The expected output would allow for this code to add the options to a dicitonary

    if args.x != None:
        print("-x options passed: ")
        cliopts = {}
        for opt in (args.x):
            # convert option=value to dictionary`your text`
            cliopts = cliopts|<opt converted to dict>
Hai Vu
  • 37,849
  • 11
  • 66
  • 93
  • 1
    Does this answer your question? [Create variable key/value pairs with argparse (python)](https://stackoverflow.com/questions/27146262/create-variable-key-value-pairs-with-argparse-python) – Abdul Aziz Barkat Aug 25 '23 at 04:15
  • you get the error because `dict('admin_directory=/var')` is not a valid way to use the `dict` function. Remember, `type` is a **function** that takes a string argument. – hpaulj Aug 25 '23 at 07:13
  • If `args.x` is a list of strings, split each on '=' and add each to a doct. – hpaulj Aug 25 '23 at 07:17
  • Yes @AbdulAzizBarkat that article is exactly what I was searching for. I was serching for 'option=value' vs Key=Value. I would have found it sooner and not needed to post. – Paul Weber Aug 25 '23 at 23:23

2 Answers2

1

Once you have a list ls with entries separated by =, you can do : {arr[0]:arr[1] for x in ls if len(arr:=x.split('='))==2 }

To create a dictionary using list compherension.

user2679290
  • 144
  • 9
0

In order to handle multiple -x, we can use a custom argparse.Action:

import argparse


class KeyValueAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        # Extract the current dictionary from the namespace
        # or create a new one
        dict_object = getattr(namespace, self.dest) or {}
        setattr(namespace, self.dest, dict_object)

        dict_object.update(kv.split("=", 1) for kv in values)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-x", nargs="*", action=KeyValueAction)
    options = parser.parse_args()
    x = options.x
    print(x)

Here is a sample interaction:

$ python3 swlist.py -x distribution_target_directory=/tmp -x admin_directory=/var
{'distribution_target_directory': '/tmp', 'admin_directory': '/var'}

Notes

  • The heart of a custom action is the __call__ function
  • In this function, we are given a namespace object. The first two lines make sure that if we have not set the attribute self.dest (which is the string 'x' in this case, then we should set it to an empty dictionary.
  • The .update call splits each value by the equal sign and update the dictionary
  • After calling parse_args, options.x will be a dictionary with all the keys/values defined from the command line.
Hai Vu
  • 37,849
  • 11
  • 66
  • 93