{"id":15433131,"url":"https://github.com/simonw/optfunc","last_synced_at":"2025-04-16T03:44:45.924Z","repository":{"id":579576,"uuid":"212454","full_name":"simonw/optfunc","owner":"simonw","description":"Syntactic sugar for creating Python command line scripts by introspecting a function definition","archived":false,"fork":false,"pushed_at":"2009-05-29T22:48:14.000Z","size":146,"stargazers_count":133,"open_issues_count":1,"forks_count":20,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-10-18T07:54:10.732Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://simonwillison.net/2009/May/28/optfunc/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"mailgun/mailgun-go","license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonw.png","metadata":{"files":{"readme":"README.txt","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-05-28T11:28:54.000Z","updated_at":"2024-02-27T08:00:12.000Z","dependencies_parsed_at":"2022-07-08T02:06:46.377Z","dependency_job_id":null,"html_url":"https://github.com/simonw/optfunc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonw%2Foptfunc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonw%2Foptfunc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonw%2Foptfunc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonw%2Foptfunc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonw","download_url":"https://codeload.github.com/simonw/optfunc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249192041,"owners_count":21227710,"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":[],"created_at":"2024-10-01T18:31:55.538Z","updated_at":"2025-04-16T03:44:45.897Z","avatar_url":"https://github.com/simonw.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"optfunc\n=======\n\nParse command line options in Python using function introspection.\n\nPost feedback here: http://simonwillison.net/2009/May/28/optfunc/\n\nI can never remember how to use any of Python's regular command line parsing\nlibraries.\n\noptfunc uses introspection to make a Python function available as a command\nline utility. It's syntactic sugar around optparse from the standard library.\n\nHere's what the API looks like so far:\n\n    import optfunc\n    \n    def upper(filename, verbose = False):\n        \"Usage: %prog \u003cfile\u003e [--verbose] - output file content in uppercase\"\n        s = open(filename).read()\n        if verbose:\n            print \"Processing %s bytes...\" % len(s)\n        print s.upper()\n    \n    if __name__ == '__main__':\n        optfunc.run(upper)\n\nAnd here's the resulting command-line interface:\n\n    $ ./demo.py --help\n    Usage: demo.py \u003cfile\u003e [--verbose] - output file content in uppercase\n    \n    Options:\n      -h, --help     show this help message and exit\n      -v, --verbose  \n    $ ./demo.py README.txt \n    OPTFUNC\n    ...\n    $ ./demo.py README.txt -v\n    Processing 2049 bytes...\n    OPTFUNC\n    ...\n\nIf you don't mind relying on some stack inspecting magic, you can replace the \n__name__ == '__main__ idiom with the following:\n\n    optfunc.main(upper)\n\nIf you like really short scripts, you can even use this function as a \ndecorator:\n\n    @optfunc.main\n    def upper(filename):\n        print open(filename).read().upper()\n\nHow arguments work\n------------------\n\nNon-keyword arguments are treated as required arguments - optfunc.run will \nthrow an error if they number of arguments provided on the command line \ndoesn't match the number expected by the function (unless @notstrict is used, \nsee below).\n\nKeyword arguments with defaults are treated as options. At the moment, only \nstring and boolean arguments are supported. Other types are planned.\n\nConsider the following:\n\n    def geocode(s, api_key='', geocoder='google', list_geocoders=False):\n\n's' is a required argument. api_key, geocoder and list_geocoders are all \noptions, with defaults provided. Since list_geocoders has a boolean as its \ndefault it will be treated slightly differently (in optparse terms, it will \nstore True if the flag is provided on the command line and False otherwise).\n\nThe command line options are derived from the parameter names like so:\n\n    Options:\n      -h, --help            show this help message and exit\n      -l, --list-geocoders\n      -a API_KEY, --api-key=API_KEY\n      -g GEOCODER, --geocoder=GEOCODER\n\nNote that the boolean --list-geocoders is a flag, not an option that sets a\nvalue.\n\nThe short option is derived from the first letter of the parameter. If that \ncharacter is already in use, the second character will be used and so on.\n\nThe long option is the full name of the parameter with underscores converted \nto hyphens.\n\nIf you want complete control over the name of the options, simply name your \nparameter as follows:\n\n    def foo(q_custom_name=False):\n\nThis will result in a short option of -q and a long option of --custom-name.\n\nSpecial arguments\n-----------------\n\nArguments with the names 'stdin', 'stdout' or 'stderr' will be automatically \npassed the relevant Python objects, for example:\n    \n    #!/usr/bin/env python\n    # upper.py\n    import optfunc\n    \n    @optfunc.main\n    def upper_stdin(stdin, stdout):\n        stdout.write(stdin.read().upper())\n\nDoes the following:\n\n    $ echo \"Hello, world\" | ./upper.py\n    HELLO, WORLD\n\nSubcommands\n-----------\n\nSome command line applications feature subcommands, with the first argument \nto the application indicating which subcommand should be executed.\n\noptfunc has the beginnings of support for this - you can pass an array of \nfunctions to the optfunc.run() and the names of the functions will be used \nto select a subcommand based on the first argument:\n\n    import optfunc\n    \n    def one(arg):\n        print \"One: %s\" % arg\n    \n    def two(arg):\n        print \"Two: %s\" % arg\n    \n    def three(arg):\n        print \"Three: %s\" % arg\n    \n    if __name__ == '__main__':\n        optfunc.run([one, two, three])\n\nUsage looks like this:\n\n    $ ./subcommands_demo.py    \n    Unknown command: try 'one', 'two' or 'three'\n    $ ./subcommands_demo.py one\n    one: Required 1 arguments, got 0\n    $ ./subcommands_demo.py two arg\n    Two: arg\n\nThis approach is limited in that help can be provided for an individual option \nbut not for the application as a whole. If anyone knows how to get optparse to\nhandle the subcommand pattern please let me know.\n\nDecorators\n----------\n\noptfunc also supports two decorators for stuff I couldn't work out how to \nshoehorn in to a regular function definition. geocode.py shows them in action:\n\n    @optfunc.notstrict\n    @optfunc.arghelp('list_geocoders', 'list available geocoders and exit')\n    def geocode(s, api_key='', geocoder='google', list_geocoders=False):\n        # ...\n\n@notstrict means \"don't throw an error if one of the required positional \narguments is missing\" - in the above example we use this because we still want\nthe list_geocoders argument to work even if a string has not been provided.\n\n@arghelp('arg-name', 'help text') allows you to provide help on individual \narguments, which will then be displayed when --help is called.\n\nTODO\n----\n\n* Support for different argument types (int, string, filehandle, choices)\n* Special handling for 'stdin' as an argument name\n* Proper unix error semantics (sys.exit(1) etc)\n* Allow the function to be a generator, print iterations to stdout\n* Support for *args (I don't think **kwargs makes sense for optfunc)\n* Subcommands need to interact with --help better\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonw%2Foptfunc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonw%2Foptfunc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonw%2Foptfunc/lists"}