I’m trying to integrate argparse into my Javascript program, such that all arguments can be loaded from an external config file, and then those values can be overridden with provided CLI arguments afterwards. To do this, I decided to read a config file & parse it into a JSON object, then iterate through the keys and set the default values in the parser, and finally parse any remaining CLI arguments to override the defaults. Unfortunately, I’m getting some strange behavior back, and since it’s a port of the Python repository there’s not much syntactically-relevant documentation (https://www.npmjs.com/package/argparse)
I have the following logic:
//readFile helper method not shown const configArgs = JSON.parse(readFile('config.json')) for (let key in configArgs) { let value = configArgs[key] //used for debugging console.log(`${key}: ${value}`) parser.set_defaults({key: value}) } var args = parser.parse_args() //used for debugging console.log(args)
However, it looks like the parser.set_defaults()
line isn’t working correctly:
path: ../data/testInput.txt json: ../build/testSet.json name: foo.txt output: output.txt Namespace(path=undefined, json=undefined, name=undefined, output=undefined, key='output.txt')
Why is it trying to create a new config option “key”, even though the key
passed into set_defaults()
is a variable & has a new value every time it’s logged to the console?
Advertisement
Answer
I contributed to this repository years ago, but haven’t worked with it or javascript recently.
In python argparse
, I think this is what you want to do:
In [27]: conf = {'path': '../data/testInput.txt', ...: 'json': '../build/testSet.json', ...: 'name': 'foo.txt', ...: 'output': 'output.txt'} In [28]: parser = argparse.ArgumentParser() In [29]: for k in conf.keys(): ...: print(k,conf[k]) ...: parser.set_defaults(**{k:conf[k]}) ...: path ../data/testInput.txt json ../build/testSet.json name foo.txt output output.txt In [30]: parser.parse_args([]) Out[30]: Namespace(path='../data/testInput.txt', json='../build/testSet.json', name='foo.txt', output='output.txt')
or simply set all keys at once:
In [31]: parser = argparse.ArgumentParser() In [32]: parser.set_defaults(**conf) In [33]: parser.parse_args([]) Out[33]: Namespace(path='../data/testInput.txt', json='../build/testSet.json', name='foo.txt', output='output.txt')
In Python (**conf)
is equivalent to (path='..data...', json='../build', etc)
.
The action of set_defaults
is to add to the _defaults
attribute:
In [34]: parser._defaults Out[34]: {'path': '../data/testInput.txt', 'json': '../build/testSet.json', 'name': 'foo.txt', 'output': 'output.txt'}
The python code is:
def set_defaults(self, **kwargs): self._defaults.update(kwargs) # and set defaults of actions if any
The corresponding javascript code is:
set_defaults(kwargs) { Object.assign(this._defaults, kwargs) # and set action.default if any
I don’t remember enough javascript to say whether that’s correct or not.