Getting Started

scriptconfig its very simple at its core. Just define a class, and then make class variables corresponding to your arguments. It works almost exactly like a dataclass.

class YourConfig(scriptconfig.DataConfig):
    argname1 = default1
    argname2 = default2

using config = YourConfig() creates an instance, which behaves like a dictionary and like parsed args. I.e. you config.argname1 or config['argname1']

Using YourConfig.cli() does the same thing but creates a parser and overloads the defaults based on sys.argv.

saying YourConfig.cli(data=kwargs) will set new defaults, but sys.argv will overwrite anything that is specified on the command line

Otherwise it behaves exactly like YourConfig(**kwargs)

Using YourConfig.cli(cmdline=False, ...) disables CLI parsing so you can force it to use the exact passed parameters (very useful when you want to invoke the CLI programatically from python, and not make an argparse object under the hood)

The main limitation of scriptconfig over argparse is that you are forced to always have a default and always use key/value argument pairs. I view this as a benefit because I want a 1-to-1 mapping between calling a script via a CLI and calling it with a kwargs configuration.

There are lots of other little things and tricks you can do, but that’s the core principle. Define a dataclass that describes your parameters and their defaults.

The other thing of note is that it does “smart” parsing by default, which I’m strongly reconsidering. So if you have the above config and run prog --argname=1 or prog --argname=foobar in the first case it will automatically figure out that you want a integer 1 and in the second case you want a string foobar.

Also --argname=True will be a boolean. I think this level of smartness is great, but what I regret adding as a feature is --argname=a,b,1,c will load as ['a', 'b', 1, 'c'], which is far too smart. A lot of time people do have commas in their arguments and they expect it to be a string by default.

Of course you can disable smart parsing by doing something like:

argname1 = scfg.Value('default1', type=str)

Specifying the type forces the argument into a standardized type, but the default under the hood is actually: argname1 = scfg.Value('default1', type=scfg.smartcast)