Productivity tool for quickly creating python programs that parse command-line arguments. Stop writing argparse boilerplate code!
Project description
duckargs 🦆
The purpose of duckargs is to save some typing whenever you want to quickly create a python program or C program that accepts command line arguments. Just run duckargs (generates python), duckargs-python (also generates python) or duckargs-c (generates C) with the arguments that you want your program to accept, with example values provided to options, and duckargs will generate the code for a program that handles those options/arguments.
Install
Install with pip (python 3x required):
pip install duckargs
Examples
Generating python code
To generate python code, run duckargs from the command line via duckargs or duckargs-python, followed by whatever arguments/options/flags you want your program to accept, and duckargs will print the corresponding python code. For example:
$ duckargs positional_arg1 positional_arg2 -i --int-val 4 -e 3.3 -f --file FILE -F --otherfile FILE -a -b -c
The output of the above command looks like this:
# Generated by duckargs, invoked with the following arguments:
# positional_arg1 positional_arg2 -i --int-val 4 -e 3.3 -f --file FILE -F --otherfile FILE -a -b -c
import argparse
def main():
parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('positional_arg1', help='a string')
parser.add_argument('positional_arg2', help='a string')
parser.add_argument('-i', '--int-val', default=4, type=int, help='an int value')
parser.add_argument('-e', default=3.3, type=float, help='a float value')
parser.add_argument('-f', '--file', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-F', '--otherfile', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-a', action='store_true', help='a flag')
parser.add_argument('-b', action='store_true', help='b flag')
parser.add_argument('-c', action='store_true', help='c flag')
args = parser.parse_args()
print(args.positional_arg1)
print(args.positional_arg2)
print(args.int_val)
print(args.e)
print(args.file)
print(args.otherfile)
print(args.a)
print(args.b)
print(args.c)
if __name__ == "__main__":
main()
Generating C code
For generating C code, the process is the same as for python code, except you should call duckargs-c instead of duckargs-python:
$ duckargs-c positional_arg1 positional_arg2 -i --int-val 4 -e 3.3 -f --file FILE -F --otherfile FILE -a -b -c
The output of the above command looks like this:
// Generated by duckargs, invoked with the following arguments:
// positional_arg1 positional_arg2 -i --int-val 4 -e 3.3 -f --file FILE -F --otherfile FILE -a -b -c
#include <stdbool.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
static char *positional_arg1 = "positional_arg1";
static char *positional_arg2 = "positional_arg2";
static long int int_val = 4;
static float e = 3.3;
static char *file = NULL;
static char *otherfile = NULL;
static bool a = false;
static bool b = false;
static bool c = false;
static struct option long_options[] =
{
{"int-val", required_argument, NULL, 'i'},
{"file", required_argument, NULL, 'f'},
{"otherfile", required_argument, NULL, 'F'},
{NULL, 0, NULL, 0}
};
void print_usage(void)
{
printf("\n");
printf("program_name [OPTIONS] positional_arg1 positional_arg2\n\n");
printf("-i --int-val [int] An int value (default: %ld)\n", int_val);
printf("-e [float] A float value (default: %.2f)\n", e);
printf("-f --file FILE A filename (default: %s)\n", file ? file : "null");
printf("-F --otherfile FILE A filename (default: %s)\n", otherfile ? otherfile : "null");
printf("-a A flag\n");
printf("-b A flag\n");
printf("-c A flag\n");
printf("\n");
}
int parse_args(int argc, char *argv[])
{
char *endptr = NULL;
int ch;
while ((ch = getopt_long(argc, argv, "i:e:f:F:abc", long_options, NULL)) != -1)
{
switch (ch)
{
case 'i':
{
int_val = strtol(optarg, &endptr, 0);
if (endptr && (*endptr != '\0'))
{
printf("Option '-i' requires an integer argument\n");
return -1;
}
break;
}
case 'e':
{
e = strtof(optarg, &endptr);
if (endptr == optarg)
{
printf("Option '-e' requires a floating-point argument\n");
return -1;
}
break;
}
case 'f':
{
file = optarg;
break;
}
case 'F':
{
otherfile = optarg;
break;
}
case 'a':
{
a = true;
break;
}
case 'b':
{
b = true;
break;
}
case 'c':
{
c = true;
break;
}
}
}
if (argc < (optind + 2))
{
printf("Missing positional arguments\n");
return -1;
}
positional_arg1 = argv[optind];
optind++;
positional_arg2 = argv[optind];
optind++;
return 0;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
print_usage();
return -1;
}
int ret = parse_args(argc, argv);
if (0 != ret)
{
return ret;
}
printf("positional_arg1: %s\n", positional_arg1);
printf("positional_arg2: %s\n", positional_arg2);
printf("int_val: %ld\n", int_val);
printf("e: %.4f\n", e);
printf("file: %s\n", file);
printf("otherfile: %s\n", otherfile);
printf("a: %s\n", a ? "true" : "false");
printf("b: %s\n", b ? "true" : "false");
printf("c: %s\n", c ? "true" : "false");
return 0;
}
Comma-separated choices for option argument
If you have an option which accepts an argument, and you write an argument string with multiple values separated by commas (e.g. -m --mode active,idle,sim), then duckargs will use the comma-separated values as a choices list for argparse, e.g.:
parser.add_argument('-m', '--mode', choices=['active', 'idle', 'sim'], default='active', help='a string')
Filenames for option arguments
If you have an option that you want to accept a filename, you have two ways to tell duckargs that the option argument should be treated as a file:
Pass the path to a file that actually exists (e.g. -f --filename file.txt) as the option argument
Pass FILE as the option argument (e.g. -f --filename FILE)
Either of which will generate a line like this:
parser.add_argument('-f', '--filename', default='file', type=argparse.FileType(), help='a filename')
Environment variables
Some things can be configured by setting environment variables.
DUCKARGS_PRINT
By default, duckargs generates a program that prints all provided arguments/options to stdout after argument parsing is complete. If you want to disable this and generate programs without the print statements, set DUCKARGS_PRINT=0 in your environment variables.
DUCKARGS_COMMENT
By default, duckargs generates a program that prints a comment header at the top, showing the arguments that duckargs was invoked with. If you want to disable this and generate programs without the comment header, set DUCKARGS_COMMENT=0 in your environment variables.
Use duckargs in python code
If you want to use duckargs in your own script, you can use the duckargs.generate_python_code and duckargs.generate_c_code functions, both of which accept a list of command line arguments:
import sys
from duckargs import generate_python_code, generate_c_code
python_code = generate_python_code(sys.argv)
c_code = generate_c_code(sys.argv)
Pitfalls
If you have a combination of flags and positional arguments, and you happen to have a flag followed by a positional argument (as in: python -m duckargs -q --quiet positional_arg), duckargs has no way to tell that you wanted a positional arg, so it will assume you want an option -q --quiet with a required argument.
To avoid this, it is recommended to declare your positional arguments first (as in: python -m duckargs positional_arg -q --quiet)
Contributions
Contributions are welcome, please open a pull request at https://github.com/eriknyquist/duckargs/pulls. You will need to install packages required for development by doing pip install -r dev_requirements.txt.
Please ensure that all existing tests pass, new test(s) are added if required, and the code coverage check passes.
Run tests with python setup.py test.
Run tests and and generate code coverage report with python code_coverage.py (this script will report an error if coverage is below 95%)
If you have any questions about / need help with contributions or tests, please contact Erik at eknyquist@gmail.com.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.