Python: how can I ingest arguments from JSON file?
Question: I have a block of python code that ingests command-line arguments, e.g.:

    
    
    import argparse
    if __name__ == "__main__":                # myScript.py
        parser = argparse.ArgumentParser()
        parser.add_argument("-i", "--int", help="Int with default", type=int, default=20)
        parser.add_argument("-swd", "--strwdef", help="string with default", type=str, default="DEFAULTSTRING")
        parser.add_argument("-snd", "--strnodef", help="string without default", type=str)
        parser.add_argument("-f", "--flag", help="binary flag", action='store_true')
        args = parser.parse_args()
        i = args.i
        swd = args.swd
        snd = args.snd
        f = args.flag
    

So this would work for a command like this:

    
    
    python myScript.py -swd SomeString --int 35 -f
    

I want to read these arguments from a JSON file instead. Questions:

  1. Are there built-in capabilities in `python 2.7` to set this up, instead of writing my own custom code of parsing results of `json.load()` to handle argument types, defaults etc?
  2. If there is, what would be the proper format for a JSON file for the example above, and the way to populate the variables `i`, `swd`, etc?

Thank you!


Answer: `args` from the parser is an `argparse.Namespace` object, with is easily
turned into a dictionary with

    
    
     vars(args)
    

`-swd SomeString --int 35 -f` would then produce something like
`namespace(swd='SomeString', int=35, f=True)`, and `{'swd':'SomeString',
'int':35, 'f':True}`.

The equivalent JSON would decode to a similar dictionary.

A dictionary can be turned (back) into a namespace with:

    
    
    In [2]: dd={'swd':'SomeString', 'int':35, 'f':True}
    In [3]: dd
    Out[3]: {'f': True, 'int': 35, 'swd': 'SomeString'}
    In [4]: argparse.Namespace(**dd)
    Out[4]: Namespace(f=True, int=35, swd='SomeString')
    

As far as I know there isn't a package that would apply `argparse` like
reasoning to a dictionary (which may have been created by `json.loads`).

Someone else recently asked if there was a way of recreating the `sys.argv`
string based on a `namespace`. You might look that up.

I can recreate a `sys.argv` like list with this code

    
    
    In [22]: def foo(k,v):
        if len(k)==1:
            k =  '-'+k
        else:
            k = '--'+k
        if isinstance(v,bool):
            return (k,)
        else:
            return k,str(v)
       ....:     
    In [23]: argv=[]
    In [24]: for k,v in dd.items():
        argv.extend(foo(k,v))
       ....:     
    In [25]: argv
    Out[25]: ['-f', '--int', '35', '--swd', 'SomeString']
    

This could then be passed to your parser with:

    
    
    args = parser.parse_args(argv)
    

========================

Another thing you could do is create a dictionary with the default values, and
update it from the JSON dictionary:

    
    
    In [27]: defaultd=dict(int=20, strwdef='DEFAULTSTRING',snd=None,flag=False)
    In [28]: defaultd
    Out[28]: {'strwdef': 'DEFAULTSTRING', 'snd': None, 'int': 20, 'flag': False}
    In [29]: defaultd.update(dd)
    In [30]: defaultd
    Out[30]: 
    {'strwdef': 'DEFAULTSTRING',
     'f': True,
     'flag': False,
     'swd': 'SomeString',
     'snd': None,
     'int': 35}
    

I just noticed a problem. For `defaultd` I used the long name 'flag' name, but
in the JSON dict I used the short 'f' name.

I could selectively copy from the JSON dict with something like:

    
    
    In [32]: for k in defaultd:
       ....:     if k in dd:
       ....:         defaultd[k]=dd[k]
       ....:         
    In [33]: defaultd
    Out[33]: {'strwdef': 'DEFAULTSTRING', 'snd': None, 'int': 35, 'flag': False}
    

Dealing with 'bad' values or aliases will be more complicated.

