{"id":19798608,"url":"https://github.com/eriknyquist/duckargs","last_synced_at":"2025-04-04T21:11:12.522Z","repository":{"id":105420678,"uuid":"609415554","full_name":"eriknyquist/duckargs","owner":"eriknyquist","description":"Code generation tool, creates python / C programs that parse command line arguments. Say bye to starting each project by reading \"argparse\" / \"geptopt.h\" docs.","archived":false,"fork":false,"pushed_at":"2025-02-05T19:23:52.000Z","size":85,"stargazers_count":116,"open_issues_count":1,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T20:08:46.906Z","etag":null,"topics":["argparse","argument-parsing","c-code-generator","c-tooling","code-generation","code-generator","code-generators","command-line-arguments","command-line-tool","command-line-tools","dev-tools","development-tools","productivity","pure-python","python","python-generator","python-tools","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eriknyquist.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-04T05:14:59.000Z","updated_at":"2025-02-05T19:23:55.000Z","dependencies_parsed_at":"2023-07-17T07:30:39.555Z","dependency_job_id":"619659f2-5ef5-4310-8084-eb66f093e3fb","html_url":"https://github.com/eriknyquist/duckargs","commit_stats":{"total_commits":31,"total_committers":1,"mean_commits":31.0,"dds":0.0,"last_synced_commit":"51e83cedc814b66ee664eeb2f4681e5219b6bec4"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fduckargs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fduckargs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fduckargs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fduckargs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eriknyquist","download_url":"https://codeload.github.com/eriknyquist/duckargs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247249532,"owners_count":20908212,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argparse","argument-parsing","c-code-generator","c-tooling","code-generation","code-generator","code-generators","command-line-arguments","command-line-tool","command-line-tools","dev-tools","development-tools","productivity","pure-python","python","python-generator","python-tools","python3"],"created_at":"2024-11-12T07:30:45.367Z","updated_at":"2025-04-04T21:11:12.496Z","avatar_url":"https://github.com/eriknyquist.png","language":"Python","readme":".. contents:: **Table of Contents**\n\n.. |duck| unicode:: 0x1F986\n\nduckargs |duck|\n---------------\n\n.. |tests_badge| image:: https://github.com/eriknyquist/duckargs/actions/workflows/tests.yml/badge.svg\n.. |cov_badge| image:: https://github.com/eriknyquist/duckargs/actions/workflows/coverage.yml/badge.svg\n.. |version_badge| image:: https://badgen.net/pypi/v/duckargs\n.. |license_badge| image:: https://badgen.net/pypi/license/duckargs\n.. |downloads_badge| image:: https://static.pepy.tech/badge/duckargs\n.. |conda_badge| image:: https://img.shields.io/conda/dn/conda-forge/duckargs.svg?label=conda-forge\n\n|tests_badge| |cov_badge| |version_badge| |license_badge| |downloads_badge| |conda_badge|\n\nBrief description\n=================\n\nThe purpose of ``duckargs`` is to save some typing whenever you want to quickly\ncreate a python program or C program that accepts command line arguments. Just run\n``duckargs`` (generates python), ``duckargs-python`` (also generates python) or\n``duckargs-c`` (generates C) with all the options/arguments that you want your program\nto accept, and ``duckargs`` will print the code for a program that handles those\noptions/arguments.\n\nLonger description\n==================\n\nIf you're like me, then you often need to create little throwaway command-line tools,\nbut *not* often enough to remember the exact syntax/details of ``argparse`` or ``getopt.h``,\nso you often start these efforts by looking up the relevant docs and refreshing your memory.\n\nNext, you spend some time typing out the boilerplate arg-parsing code, with one eye\non the docs, and eventually (depending on how much arg-parsing boilerplate code you need)\nyou may forget some interesting detail that was part of your original idea, or you may\njust get sick of it and decide that you don't event *need* a command-line tool, and\nyou'll do the thing manually instead.\n\n``duckargs`` makes this process a little bit simpler, and shortens the time between your\nidea and having a working C or Python program.\n\nLet's imagine that you want to create a little command-line tool that accepts the\nfollowing command line options/arguments:\n\n* A positional argument, string\n* An optional integer value (``-i`` or ``--intval``)\n* An optional float value (``-f`` or ``--floatval``)\n* A flag (``-q``)\n\nYou can run ``duckargs`` and pass all those options/arguments/flags, and ``duckargs`` will\ngenerate a working program with all the boilerplate taken care of:\n\n**Generating Python**\n\n.. code::\n\n    $ duckargs somestring -i --intval 99 -f --floatval 7.7 -q\n\n**Output**\n\n.. code::\n\n    # Generated by duckargs, invoked with the following arguments:\n    # somestring -i --intval 99 -f --floatval 7.7 -q\n\n    import argparse\n\n    def main():\n        parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',\n                                         formatter_class=argparse.ArgumentDefaultsHelpFormatter)\n\n        parser.add_argument('somestring', help='a string')\n        parser.add_argument('-i', '--intval', default=99, type=int, help='an int value')\n        parser.add_argument('-f', '--floatval', default=7.7, type=float, help='a float value')\n        parser.add_argument('-q', action='store_true', help='q flag')\n        args = parser.parse_args()\n\n        print(args.somestring)\n        print(args.intval)\n        print(args.floatval)\n        print(args.q)\n\n    if __name__ == \"__main__\":\n        main()\n\n**Generating C**\n\n.. code::\n\n    $ duckargs-c somestring -i --intval 99 -f --floatval 7.7 -q\n\n**Output**\n\n.. code::\n\n    // Generated by duckargs, invoked with the following arguments:\n    // somestring -i --intval 99 -f --floatval 7.7 -q\n\n    #include \u003cstdbool.h\u003e\n    #include \u003cgetopt.h\u003e\n    #include \u003cstdlib.h\u003e\n    #include \u003cstdio.h\u003e\n\n    static char *somestring = \"somestring\";\n    static long int intval = 99;\n    static float floatval = 7.7;\n    static bool q = false;\n\n    static struct option long_options[] =\n    {\n        {\"intval\", required_argument, NULL, 'i'},\n        {\"floatval\", required_argument, NULL, 'f'},\n        {NULL, 0, NULL, 0}\n    };\n\n    void print_usage(void)\n    {\n        printf(\"\\n\");\n        printf(\"USAGE:\\n\\n\");\n        printf(\"program_name [OPTIONS] somestring\\n\");\n        printf(\"\\nOPTIONS:\\n\\n\");\n        printf(\"-i --intval [int]      An int value (default: %ld)\\n\", int);\n        printf(\"-f --floatval [float]  A float value (default: %.2f)\\n\", float);\n        printf(\"-q                     A flag\\n\");\n        printf(\"\\n\");\n    }\n\n    int parse_args(int argc, char *argv[])\n    {\n        char *endptr = NULL;\n        int ch;\n\n        while ((ch = getopt_long(argc, argv, \"i:f:q\", long_options, NULL)) != -1)\n        {\n            switch (ch)\n            {\n                case 'i':\n                {\n                    intval = strtol(optarg, \u0026endptr, 0);\n                    if (endptr \u0026\u0026 (*endptr != '\\0'))\n                    {\n                        printf(\"Option '-i' requires an integer argument\\n\");\n                        return -1;\n                    }\n                    break;\n                }\n                case 'f':\n                {\n                    floatval = strtof(optarg, \u0026endptr);\n                    if (endptr == optarg)\n                    {\n                        printf(\"Option '-f' requires a floating-point argument\\n\");\n                        return -1;\n                    }\n                    break;\n                }\n                case 'q':\n                {\n                    q = true;\n                    break;\n                }\n            }\n        }\n\n        if (argc \u003c (optind + 1))\n        {\n            printf(\"Missing positional arguments\\n\");\n            return -1;\n        }\n\n        somestring = argv[optind];\n\n        return 0;\n    }\n\n    int main(int argc, char *argv[])\n    {\n        if (argc \u003c 2)\n        {\n            print_usage();\n            return -1;\n        }\n\n        int ret = parse_args(argc, argv);\n        if (0 != ret)\n        {\n            return ret;\n        }\n\n        printf(\"somestring: %s\\n\", somestring ? somestring : \"null\");\n        printf(\"intval: %ld\\n\", intval);\n        printf(\"floatval: %.4f\\n\", floatval);\n        printf(\"q: %s\\n\", q ? \"true\" : \"false\");\n\n        return 0;\n    }\n\nInstall\n=======\n\nInstall with pip (python 3x required):\n\n::\n\n    pip install duckargs\n\nComma-separated choices for option argument\n===========================================\n\nIf you have an option which accepts an argument, and you write an argument string with\nmultiple values separated by commas (e.g. ``-m --mode active,idle,sim``), then generated \npython code will use the comma-separated values as a ``choices`` list for argparse:\n\n.. code:: python\n\n    parser.add_argument('-m', '--mode', choices=['active', 'idle', 'sim'], default='active', help='a string')\n\nAnd generated C code will use the comma-separated values to restrict values in a similar manner:\n\n.. code:: c\n\n    static char *mode_choices[] = {\"active\", \"idle\", \"stop\"};\n    static char *mode = \"active\";\n\n    static struct option long_options[] =\n    {\n        {\"mode\", required_argument, NULL, 'm'},\n        {NULL, 0, NULL, 0}\n    };\n\n    void print_usage(void)\n    {\n        printf(\"\\n\");\n        printf(\"USAGE:\\n\\n\");\n        printf(\"program_name [OPTIONS]\\n\");\n        printf(\"\\nOPTIONS:\\n\\n\");\n        printf(\"-m --mode [active|idle|stop]  A string value (default: %s)\\n\", mode ? mode : \"null\");\n        printf(\"\\n\");\n    }\n\n    int parse_args(int argc, char *argv[])\n    {\n        int ch;\n\n        while ((ch = getopt_long(argc, argv, \"m:\", long_options, NULL)) != -1)\n        {\n            switch (ch)\n            {\n                case 'm':\n                {\n                    mode = optarg;\n                    for (int i = 0; i \u003c 3; i++)\n                    {\n                        if (0 == strcmp(mode_choices[i], mode))\n                        {\n                            break;\n                        }\n                        if (i == 2)\n                        {\n                            printf(\"Option '-m' must be one of ['active', 'idle', 'stop']\\n\");\n                            return -1;\n                        }\n                    }\n                    break;\n                }\n            }\n        }\n\n        return 0;\n    }\n\nFilenames for option arguments\n==============================\n\nIf you have an option that you want to accept a filename, you have two ways to tell\n``duckargs`` that the option argument should be treated as a file:\n\n* Pass the path to a file that actually exists (e.g. ``-f --filename file.txt``)\n  as the option argument\n\n* Pass ``FILE`` as the option argument (e.g. ``-f --filename FILE``)\n\nEither of which will generate python code like this:\n\n.. code:: python\n\n    parser.add_argument('-f', '--filename', default='file', type=argparse.FileType(), help='a filename')\n\nAnd will generate C code like this:\n\n.. code:: c\n\n    static char *filename = NULL;\n\n    static struct option long_options[] =\n    {\n        {\"filename\", required_argument, NULL, 'f'},\n        {NULL, 0, NULL, 0}\n    };\n\n    void print_usage(void)\n    {\n        printf(\"\\n\");\n        printf(\"USAGE:\\n\\n\");\n        printf(\"program_name [OPTIONS]\\n\");\n        printf(\"\\nOPTIONS:\\n\\n\");\n        printf(\"-f --filename FILE  A filename (default: %s)\\n\", filename ? filename : \"null\");\n        printf(\"\\n\");\n    }\n\n    int parse_args(int argc, char *argv[])\n    {\n        int ch;\n\n        while ((ch = getopt_long(argc, argv, \"f:\", long_options, NULL)) != -1)\n        {\n            switch (ch)\n            {\n                case 'f':\n                {\n                    filename = optarg;\n                    break;\n                }\n            }\n        }\n\n        return 0;\n    }\n\nEnvironment variables\n=====================\n\nSome things can be configured by setting environment variables.\n\n``DUCKARGS_PRINT``\n##################\n\nBy default, ``duckargs`` generates a program that prints all provided arguments/options\nto stdout after argument parsing is complete.\nIf you want to disable this and generate programs without the print statements, set\n``DUCKARGS_PRINT=0`` in your environment variables. This environment variable affects\ngenerated C code and generated python code.\n\n``DUCKARGS_COMMENT``\n####################\n\nBy default, ``duckargs`` generates a program that prints a comment header at the top,\nshowing the arguments that ``duckargs`` was invoked with. If you want to disable this and\ngenerate programs without the comment header, set ``DUCKARGS_COMMENT=0`` in your environment\nvariables. This environment variable affects generated C code and generated python code.\n\nUse duckargs in python code\n===========================\n\nIf you want to use duckargs in your own script, you can use the ``duckargs.generate_python_code`` and\n``duckargs.generate_c_code`` functions, both of which accept a list of command line arguments:\n\n.. code:: python\n\n    import sys\n    from duckargs import generate_python_code, generate_c_code\n\n    python_code = generate_python_code(sys.argv)\n\n    c_code = generate_c_code(sys.argv)\n\nPitfalls\n========\n\nIf you have a combination of flags and positional arguments, and you happen to have a flag\nfollowed by a positional argument (as in: ``python -m duckargs -q --quiet positional_arg``),\n``duckargs`` has no way to tell that you wanted a positional arg, so it will assume you want\nan option ``-q --quiet`` with a required argument.\n\nTo avoid this, it is recommended to declare your positional arguments first (as in: ``python -m duckargs positional_arg -q --quiet``)\n\nContributions\n=============\n\nContributions are welcome, please open a pull request at `\u003chttps://github.com/eriknyquist/duckargs/pulls\u003e`_.\nYou will need to install packages required for development by doing ``pip install -r dev_requirements.txt``.\n\nPlease ensure that all existing tests pass, new test(s) are added if required, and the code coverage\ncheck passes.\n\n* Run tests with ``python setup.py test``.\n* Run tests and and generate code coverage report with ``python code_coverage.py``\n  (this script will report an error if coverage is below 95%)\n\nIf you have any questions about / need help with contributions or tests, please\ncontact Erik at eknyquist@gmail.com.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriknyquist%2Fduckargs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feriknyquist%2Fduckargs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriknyquist%2Fduckargs/lists"}