Easy Python CLI with Click
codingwithricky.com
codingwithricky.com
In any case, comparing a stdlib library to a 3rd party one is a bit apples to oranges. Most people first decide whether or not they want to use pypi packages, and then start evaluating which ones are appropriate.
I don't think it's as binary as this. There should be, at least intuitively, a mild negative bias to adding a marginal dependency, even once you're dependent on pypi. We're lucky enough to not be dealing with a dumpster fire ecosystem like nodejs, but it's still a good habit.
For me, writing your interface with click doesn't seem too much better than writing it with argparse, certainly not enough to get over the (small) activation energy of a non-stdlib dependency
but if you just have some basic script to scrape some logs or zip up files, its nice to have it be self contained
1. Nothing stays a simple as time happens. New shit gets added.
2. Eventually people do want to use libraries so you're back to square 1.
3. It's "cross-platform" runnable now so those annoying macOS and Windows users can suddenly use it. Though depending on how you do the shim it might be tricky. I've taken to writing the shim in Go lately so I can poop out a static binary that does the rest of the work.
4. It's really easy to keep stuff up to date if your users are non-technical... simply have the shim docker pull a new version on startup.
To the end user it requires just a single artifact. For the developer there's a bit more stuff to manage but it's not exactly like any of this is hard stuff to figure out.
#!/usr/bin/env python3
“””
Usage: ./myscript.py <arg> [<optionalarg>]
“””
from docopt import docopt
if __name__ == ‘__main__’:
args = docopt(__doc__)
print(args[‘<arg>’], args[‘<optionalarg>’] or ‘foo’)
[0]: https://github.com/docopt/docopt> On top of that docopt is restricted to basic parsing. It does not handle argument dispatching and callback invocation or types. This means there is a lot of code that needs to be written in addition to the basic help page to handle the parsing results.
1. http://click.palletsprojects.com/en/7.x/why/#why-not-docopt-...
I drop a doc-string like this one in every build script and get the command line interfaces for free:
"""
Install:
pipenv install --dev
Usage:
make.py [<command>] [options]
Commands:
build Build wheel.
push Push wheel to pypi.
test Run tests.
bump Run interacitve bump sequence.
git Run interactive git sequence.
Options:
-h, --help Show this screen.
"""I do concede that click may be better for CLI apps that grow to tens of thousands of LOC and involve multiple full-time developers. I've never built one that big though.
I also worry a bit that docopt doesn't seem to have gotten much attention in a while. It's basically complete, so shouldn't matter, but still.
def hello(name):
return "hello {}".format(name)
def ping():
return "pong"
if __name__ == "__main__":
import argh
parser = argh.ArghParser()
parser.add_commands([hello, ping])
parser.dispatch()Personally I'll probably stick to argh, but good to see some competition in the space.
One nice thing about argh is that it's mostly just a fancy wrapper around argparse. So you have the full functionality of argparse if you need it, while still getting the lack of boilerplate and nice defaults of argh.
It also means it works with other third party things on top of argparse like argcomplete for tab completion.
Does anyone know if Click is similar, or if it implements its own parser?
EDIT: Answered my own question. Looks like it uses optparse internally. So yeah, should see similar benefits.
Sounds fun, great coworking environment.
Caveat: Click's docs were out of date and had open bugs for what feels like years until it finally updated to 7. version 6 was "unstable" https://github.com/pallets/click/issues/503. Hopefully it's over now.
Good things:
- More concise than standard library argparse
- Testing via CliRunner (http://click.palletsprojects.com/en/7.x/testing/), example: https://github.com/tmux-python/tmuxp/blob/v1.5.3/tests/test_...
Feel free to study / copy from mine if you like (license MIT):
- https://cihai-cli.git-pull.com/: https://github.com/cihai/cihai-cli/blob/v0.5.0/cihai_cli/cli...
- https://tmuxp.git-pull.com/: https://github.com/tmux-python/tmuxp/blob/v1.5.3/tmuxp/cli.p...
- https://vcspull-git-pull.com/: https://github.com/vcs-python/vcspull/blob/v1.2.0/vcspull/cl...
Plus it comes with some useful utilities you might need in a cli to show a progressbar, display color, open test in a pager/an editor etc.
The official doc is really nice and gives it more justice than this blog post: https://click.palletsprojects.com/en/7.x.
So many of these parsing libraries seem to forget that any positional parameter can stop options parsing not just '--' and that that parameter might appear arbitrarily deep in subcommands.
This is not only needed for commands like sudo and ssh but BSD style CLIs as well which all OSX users are probably intimately familiar and annoyed with.
With every other tool I’ve tried, I end up writing a python API and a CLI and documenting it twice.
Defopt eliminates that almost completely (but with *args still allows for elegant interfaces)
Critiques of any library are great, but you need to expand on vague points: "I also doubt that click does decorators correctly too", or how you would ever expect them (or even want them??) to work on an instance method. It might be that you're misunderstanding the library and how it should be used rather than it being not worth using.
I find it absolutely perfect for a lot of situations.