9 ms·
Click – Python library for command-line interfaces
- Spiritus 12y agohttps://github.com/mitsuhiko/click https://github.com/mitsuhiko/click
- hoodoof 12y agoGorgeous. This guy has a full time job, a wife, and wrote Flask and Werkzeug, ItsDangerous, Sphinx, Markupsafe, Jinja2 (and Jinja) and that's just some of the well known stuff. Handsome and young too. Bastard. He probably saves the world in a dinner jacket in his spare time.
- edward 12y agoSphinx was written by Georg Brandl, not by Armin Ronacher.
- hoodoof 12y agoHmmm. It's listed on his projects page...... https://lucumr.pocoo.org/projects/ https://lucumr.pocoo.org/projects/
- the_mitsuhiko 12y agoI worked with Georg on it, but the bulk of the code is from him.
- lftl 12y agoTo be fair he only got married this month, so the jury is still out on where his productivity goes from here ;)
- agentultra 12y agoGetting married didn't kill me it was having a kid. Now I get maybe four hours a week for hobby/OSS programming.
- msvalkon 12y agoThis is true. I have two now. Personal time is now a dusty concept.
- the_mitsuhiko 12y agoGiven that I wrote parts of this on my honeymoon I think it helped. Fingers crossed :)
- Cyph0n 12y agoYou never cease to amaze :D
- mixmastamyk 12y agoThat's actually not a good sign for future marital bliss.
- megabulldog 12y agoo rly? ;)
- Goopplesoft 12y agoArmin Ronacher is absolutely amazing at python. If you want to learn some things dive into his source code and dig away. He really thinks through code architecture.
- zhaphod 12y agoI am already on this. Not gonna stop till I read up on all of his code. Its a plane, its a bird, No its kick ass python programmer. :).
- Cyph0n 12y agoNot only that, but Armin is a master at writing documentation for his libraries. I wish I could be as good as him.
- sotte 12y agoDoes anybody know docopt? I really like it because you simply write the help/usage as text and docopt automatically generates the parser for it. Take a look at the example in the README: https://github.com/docopt/docopt https://github.com/docopt/docopt
- denibertovic 12y agoI'm using docopt....It's really nice with it's automagicness. But for some stuff it's just not enough, too unflexible. I'm really excited about click.
- pandatigox 12y agoKudos again to the pocoo team for creating such a simple and useful library. It sure beats optparse :) On a side note, however, does anyone know why the team prefers to wrap functions in decorators? Flask also uses them, but what's the design decision behind them?
- hoodoof 12y agoDecorators are so simple and minimalistic and elegant and easy to understand. They can surface an arbitrary amount of extra functionality with a single statement. For example, ensure a function is only accessible to authenticated users by simply saying something like @requires_authenticated_user. Another example would be to create a logging decorator to wrap a function or a class to create a log of every time the function is accessed @log_function_access. Or to wrap a function to ensure that every access to the properties of that function are pushed through some sort of validation or transformation @validate_set or @transform_get. Decorators allow encapsulation of functions within other functional concepts with almost no code, that's the design decision for using them.
- HeyImAlex 12y agoYep, it's best us case is basically acting as pythons anonymous function (since lambdas suck for everything but the most trivial things). Where in js flask might read app.route('/', function(){//do something}); python uses a decorator right above a regular function definition. The alternative is to manually add it after it's defined (in flask that's add_url_rule), but that kind of hides the intent of the function and is more cumbersome as you need to manually pass in the fn name.
- gbog 12y agoThis is a valid question. When things become complex I found that decorator is a bit too magic, and should be used with moderation.
- eeadc 12y agoLooks like a nice wrapper around argparse: https://docs.python.org/3/library/argparse.html https://docs.python.org/3/library/argparse.html
- rjgray 12y agoIt's a wrapper around optparse, as per http://click.pocoo.org/why/ http://click.pocoo.org/why/. I'm curious about that decision given that optparse is deprecated. It says it's because argparse doesn't allow nested commands, but I don't really see why that feature is so desirable as to warrant using a deprecated module. I probably need to have a play with it to find out. Looks like a nice module.
- the_mitsuhiko 12y agoClick can be extended lazily which helps execution time a lot when working with many, many plugins. It also can be extended at runtime as per configuraton. argparse requires the parser to have full knowledge of everything which makes it slow if you add many commands. Biggest problem though is that it's parsing system is a bit broken when it comes to escaping. Options with arguments cannot have values starting with dashes which is problematic for delegating subcommands to other things. For what I wrote Click for I could not find any alternatives that worked that way besides optparse itself but that is hard to use.
- sophacles 12y agoCan you provide an example of what you're saying? I've found that argparse.ArgumentParser.parse_known_args() and sub-parsers can do everything I can see click doing. Including lazy loading of plugins and the like.
- the_mitsuhiko 12y agoArgparse has too magic of a design that you could fully nest it. I tried it many times but you always run into it's limitations. Links to some open bugs on it: * http://bugs.python.org/issue13966 * http://bugs.python.org/issue14191
- tudborg 12y agoIt looks really well done. I still prefer docopt (https://github.com/docopt/docopt https://github.com/docopt/docopt) . It is so much simpler to use. Click seems to be a bit overengineered.
- ramblerman 12y agoAs someone who has never used either, the documentation and simple example of Click won hands down. I could use it for simple cases within 15 seconds of reading. Docopt not so much.
- aidos 12y agoYou're right - looking on the http://docopt.org/ http://docopt.org/ page it's not immediately obvious how it works. The general idea is that you don't specify any code, you just give the help message as text. Docopt parses that to figure out all the options etc and convert those into the parameters coming in to your system. It's a really clever idea. You specify the human interface, docopt converts that into the code version (so long as you adhere to a few common conventions). I haven't seen a cleaner system anywhere. From their example: """Naval Fate. Usage: naval_fate.py ship new <name>... naval_fate.py ship <name> move <x> <y> [--speed=<kn>] naval_fate.py ship shoot <x> <y> naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting] naval_fate.py (-h | --help) naval_fate.py --version Options: -h --help Show this screen. --version Show version. --speed=<kn> Speed in knots [default: 10]. --moored Moored (anchored) mine. --drifting Drifting mine. """ from docopt import docopt if __name__ == '__main__': arguments = docopt(__doc__, version='Naval Fate 2.0') print(arguments)
- voltagex_ 12y agoThat's brilliant. I wonder if there's a way to use docstrings like that to create REST services in Flask.
- buster 12y agoI've used docopt for some tools, but argtools (and click it seems) is much more convenient, imo. It's very easy to remember the 1-2 decorators and probably most importantly, the command arguments and everything else are where the command is defined, not somewhere else. When using docopt i spent much more time defining the docstring and figuring out the right way to write it, especially more complex scenarios.
- lorenzfx 12y agoThis looks pretty similar to aargvard [1] (which is, as stated in the README, inspired by flask). [1] https://github.com/DasIch/argvard https://github.com/DasIch/argvard
- waitingkuo 12y agoTime to rewrite some of my dirty command-line programs
- buster 12y agoLooks nice but the example looks almost exactly like https://pypi.python.org/pypi/argtools/0.1.2 https://pypi.python.org/pypi/argtools/0.1.2
- thu 12y agoThe biggest gripe I have with using Python for rich command-line tool is the startup time. One of the first reason I like to write a nice command-line tool when I start a project, say foo, is to be able to do `foo --help` to quickly see and remember what the project can do (I have a very bad memory and doing this makes it possible for me to jump back faster to a project, even well documented. I can forget what I was doing in just a few days and so I add a lot of small commands). In short running `foo --help` should be instant and if it loads all its modules to list the different sub-commands and their respective description it is really too slow. A possibility is to cache some information (e.g. generate a text file or a small Python script).
- stdbrouw 12y agoHm, it'd be pointless to argue this point (if you think it's slow then it's slow) but I've created many a Python CLI and have never noticed them being slow to start. Perhaps it's a case of importing certain modules globally instead of on a per-function basis?
- thu 12y agoSee my answer to coldtea. Yes you can organize you're code to help making it load faster but I don't think it is fast enough. Maybe my terminal is slow, maybe my machine is slow (and maybe I'm overly sensitive to the problem) but the difference is telling.
- coldtea 12y ago>The biggest gripe I have with using Python for rich command-line tool is the startup time. What startup time? I even have a python script running on every shell prompt drawing (that checks mercurial on top of starting the python interpreter), and the latency is negligible.
- thu 12y agoI just tried on an app at work (Django app): > time python manage.py --help real 0m0.473s user 0m0.240s sys 0m0.148s Half of a second is very noticeable (and annoying). I had similar perception in my previous work. You can try to only load enough to display the help text without really loading everything, but that doesn't work that well (you have to organize things differently, and `--help` requires to load a lot of stuff. `subcommand --help` needs less but it still has to see if the subcommand exists). As a reference: > time python -c 'print "hello"' hello real 0m0.041s user 0m0.024s sys 0m0.012s > time echo hello hello real 0m0.000s user 0m0.000s sys 0m0.000s Actually even the first (0.041s) is not instant, while the second one does (I mean as I perceive it visually).
- nubela 12y agoAhh.. I really like pocoo's products. But I've found manage.py (https://github.com/Birdback/manage.py https://github.com/Birdback/manage.py) to be far leaner and simple. What do you guys think?
- anentropic 12y agodon't like that, clashes with Django
- mborch 12y agoI think this is intentional. Django's manage command is already extensible, so if you're using Django then perhaps it's best to use its tool chain.
- deleted 12y ago[deleted]
- peterjs 12y agoOn a related note. Which python library would you recommend for text-based interfaces? I have never used ncurses, so I don't know how complex it is. What I would like to achieve is having a user launch my script from the command line, use the text based interface to select a source and destination folder, set a few parameters and show a progress bar.
- phaer 12y agoI'd say http://urwid.org/ http://urwid.org/ should be the best choice for something like that. The main alternative would be to hack it together by yourself using https://docs.python.org/3.4/library/curses.html https://docs.python.org/3.4/library/curses.html
- SEJeff 12y agoUrwid is definitely the nicest of the curses widget frameworks I've used for python.
- abecedarius 12y agohttps://github.com/thomasballinger/curtsies https://github.com/thomasballinger/curtsies looks well-designed. (I haven't tried it yet. What I do is code to ANSI terminal codes directly: e.g. https://github.com/darius/sketchbook/blob/master/misc/sokoban.py https://github.com/darius/sketchbook/blob/master/misc/sokoba...)
- jojoo 12y agoIt's also possible and very easy to do this with python-dialog[0] or with whiptail[1] (no progress bar). downside: both need external binarys. [0]: http://pythondialog.sourceforge.net/ http://pythondialog.sourceforge.net/ [1]: https://github.com/marwano/whiptail https://github.com/marwano/whiptail
- eddd 12y agohttps://readthedocs.org/projects/argh/ https://readthedocs.org/projects/argh/
- dankilman 12y agoI also really like argh, though it seems the provided link documents an api the mandates decorators and in fact what I like about argh is that functions can remain clean. http://argh.readthedocs.org/en/latest/ http://argh.readthedocs.org/en/latest/
- icebraining 12y agoYou're never forced to use decorators, they're just syntactic sugar. Their example: @click.command() @click.option('--count', default=1, help='number of greetings') @click.option('--name', prompt='Your name', help='the person to greet', required=True) def hello(count, name): for x in range(count): print('Hello %s!' % name) Could be written as: def hello(count, name): for x in range(count): print('Hello %s!' % name hello = click.option('--name', prompt='Your name', help='the person to greet', required=True)(hello) hello = click.option('--count', default=1, help='number of greetings')(hello) hello = click.command(hello)
- u124556 12y agoThe command decorator is nice, but the group decorator feels wrong, why create a function that does nothing just to decorate it? I'd rather use `cli = click.Group()`.
- clarkevans 12y agoIt seems to me that there are a few projects similar this. Here is another, https://pypi.python.org/pypi/Cogs/ https://pypi.python.org/pypi/Cogs/ (conceptualized as a "Makefile" replacement). I'm wondering if there could be a breakout at the next PyCon to see if we could discuss approaches and come up with a unified way to do convert Python libraries into command line scripts?
- toyg 12y agoYeah, plenty: - Cliff http://cliff.readthedocs.org/en/latest/ http://cliff.readthedocs.org/en/latest/ - docopt http://docopt.org http://docopt.org - argparse - optparse etc etc etc...
- naiquevin 12y agoThere's also Clint by Kenneth Reitz (https://github.com/kennethreitz/clint https://github.com/kennethreitz/clint)
- douglarek 12y agoClint is a cmd tool not parsing tool
- windexh8er 12y agoAnd the author acknowledges that: "There are many alternatives to click and you can have a look at them if you enjoy them better. The obvious ones are optparse and argparse from the standard library. click is actually implemented as a wrapper around optparse and does not implement any parsing itself. The reason it’s not based on argparse is that argparse‘s design does not allow proper nesting of commands by design and has some deficiencies when it comes to POSIX compliant argument handling." What I love about Pocoo is they always have stellar documentation and give clear rationale - from the beginning.
- vonmoltke 12y agoDoes that mean optparse will be maintained along with click? optparse has been deprecated in favor of argparse since 2.7/3.2.
- bru 12y ago>You can get the library directly from PyPI: >pip install click Well... no you cannot. See the page: https://pypi.python.org/pypi/click https://pypi.python.org/pypi/click The package hasn't been uploaded yet. However one can install it straight from the git repo: > pip install git+ssh://git@github.com:mitsuhiko/click.git
- philtar 12y ago> pip install git+ssh://git@github.com:mitsuhiko/click.git Can someone comment regarding using pip like that? Is it fine to put this on req.txt? Any best practices somewhere?
- toyg 12y agoThat syntax is usually meant for packages that you want to edit after installation (with -e). If you plan to release your stuff, the dependencies in your req.txt should be as pinned as possible. The classic example is Requests: when it changed the API fairly significantly, umpteen installers broke... just because people did not bother with specifying a version for that lib.
- berdario 12y agoYou can also install straight from a github tarballs: pip install "https://github.com/mitsuhiko/click/tarball/master#egg=click" https://github.com/mitsuhiko/click/tarball/master#egg=click" to pin a specific revision: pip install "https://github.com/mitsuhiko/click/tarball/5b7b7296fabc5d47d4ffd179be52492095e36f30#egg=click" https://github.com/mitsuhiko/click/tarball/5b7b7296fabc5d47d... (btw, it seems bad practice to add such a link as a dependency in your setup.py... usually you'd do it for temporary shallow forks, but otherwise I think it'd be better to also upload your shallow fork on pypi ...I guess you can just remove it from pypi if it won't be needed anymore)
- chiachun 12y agoI think that's because it hasn't been released yet. The author(s) may just want some feedback or opinions first.
- tiziano88 12y agois there anything like this for Go?
- jebus989 12y agoCan't say I've tried it but the above-mentioned docopt has a Go implementation: https://github.com/docopt/docopt.go https://github.com/docopt/docopt.go
- jobeirne 12y agoThis doesn't look much different than argh, which has been around for ages: http://argh.readthedocs.org/en/latest/tutorial.html http://argh.readthedocs.org/en/latest/tutorial.html
- _ZeD_ 12y agodo you know plac[0]? [0] https://pypi.python.org/pypi/plac https://pypi.python.org/pypi/plac
- the_mitsuhiko 12y agoI did not expect this to be on hackernews this early. I want to point out that I have not made a release yet and it's not yet feature complete. Mainly I want to ask for feedback on the general design.
- seaneagan 12y agoI have a very similar library for the Dart programming language: https://github.com/seaneagan/unscripted https://github.com/seaneagan/unscripted Checkout the github issues there for some features I want to add, like bash completion support for example. I think we can steal ideas from each other! One nice thing about dart's annotations vs. python's decorators is they can be placed on a function's parameters as well, so it allows the option/flag/argument declarations to be a bit more DRY.
- timtadh 12y agoArmin, my feedback is in the form of my own version of this library.[1] I have been working on this on and off for some time and like you have not made a release. That said, I have been using it quite a bit both in my research and at work and I think it helps. The main idea behind it is make it easy to write a "getopt" style program with arbitrary command nesting. I have found that although argparse and sisters are nice libraries they don't allow me to do many of things I like to do in my interfaces. For instance sometimes like options such as foo -x a -x y -x q ... where I would process that into like so: extras = list() for opt, arg in opts: if opt in ('-h', '--help',): util.usage() ... elif opt in ('-x', '--extra'): extras.append(validate_or_die(arg)) I also believe that you should have "fast fail" validators. So I have several in `optutils` which are like: util.assert_dir_exists(path) which if a directory doesn't exist on the path it creates it. If there is already a file there and it isn't a directory it dies with an error. When it dies, I try and have unique exit codes for various errors (for testability) and provide usage information immediately. This style is nice because it provides immediate feedback to the user with no fuss. I think a lot of "option parser frameworks" miss the point in having lots of things for parsing ints and things. Most of the time I deal with files, directories, and "string" parameters which these libraries don't help with. In general, the standard libraries make it way to hard to write really nice command line tools. I like some things about your library, but I think that you need to increase the flexibitly for how options are processsed to you can do whatever you want with them. I also think that option parsing and configuration should be integrated. I am working to support that but I am not there yet. (see optutils/conf.py for my current ideas) [1] https://github.com/timtadh/optutils https://github.com/timtadh/optutils
- moondowner 12y agoLittle unfortunate naming. Isn't Click a trademark of ASF? http://click.apache.org/ http://click.apache.org/
- deleted 12y ago[deleted]
- pekk 12y agoThere are like 20 libraries for this already and this looks very similar to those. But Armin Ronacher, therefore it will be popular
- xiaq 12y agoA bit off-topic, but I like how pocoo.org uses different fonts for different projects: Flask: Georgia for text, Garamond for titles Werkzeug: Lucida Grande for text, Ubuntu for titles And now click: Ubuntu Mono for text, Open Sans for titles
- gojomo 12y agoI had the same thought, and will almost certainly be cribbing this page's body-text font stack... font-family: 'Ubuntu Mono','Consolas','Menlo','Deja Vu Sans Mono','Bitstream Vera Sans Mono'; ...(fulfilled by Menlo on my Mac) for a future project.
- erlkonig 12y agoWhy is it that (nearly) every description I read about some random new Python command wrapper fails to get the "python" and ".py" out of the command examples, even in Linux? I don't blame this particular offering, since I don't think release was actually planned just yet and any number of other projects have made the same subtle mistake. Command Name Extensions are Harmful. Don't expose such an implementation detail in every example, lest everyone actually follow them. Use the "#!/usr/bin/env python" or whatever at the top of your scripts. And yes, you can keep the .py if what you have is a library, not just a command (but it's nice to then make a wrapper the doesn't expose the implementation language). And obviously in other OSes where the command extension can be omitted and still work this isn't such a big deal. But in Unix/Linux, commands should be reimplementable in a different language without making some .(extension) a like, retained to keep from breaking other things that depend on it. Just say no :-)
- Tyr42 12y agoDid you see the last part on setuptools? It actually shows you how to set it up so you don't even use a #!, but rely on setuptools to make an executable for you, that'll work in a vitualenv or on windows. And the script name doesn't have .py at the end in his example, though he doesn't call that out specifically.
- gdw2 12y agoReminds me of Commandr. Both use decorators. https://github.com/tellapart/commandr https://github.com/tellapart/commandr
- kylemaxwell 12y agoTrying to figure out how this compares to Naked (http://naked-py.com http://naked-py.com) in terms of goals.
- mahmoudimus 12y agoI should write up a comparison between: - Cement (http://builtoncement.com http://builtoncement.com) - Cliff (http://cliff.readthedocs.org/en/latest/ http://cliff.readthedocs.org/en/latest/) - Plumbum (http://plumbum.readthedocs.org http://plumbum.readthedocs.org) - Argh (https://pypi.python.org/pypi/argh/0.24.1 https://pypi.python.org/pypi/argh/0.24.1) - Aaargh (https://github.com/wbolster/aaargh https://github.com/wbolster/aaargh) - Baker (https://pypi.python.org/pypi/Baker/ https://pypi.python.org/pypi/Baker/) So many more to choose from. Now we get to evaluate Click. Seems like the reason Armin wrote Click was to load options dynamically, but that's what Cliff does via stevedore (https://github.com/dreamhost/stevedore https://github.com/dreamhost/stevedore). My favorite feature about Cliff though is: http://cliff.readthedocs.org/en/latest/complete.html http://cliff.readthedocs.org/en/latest/complete.html which comes out of the box, but then again, there's Argcomplete (https://github.com/kislyuk/argcomplete https://github.com/kislyuk/argcomplete). EDIT: Updating from previous posters - Naked (http://naked-py.com http://naked-py.com) - Docopt (http://docopt.org http://docopt.org) - Clint (https://github.com/kennethreitz/clint https://github.com/kennethreitz/clint) - Argvard (https://github.com/DasIch/argvard https://github.com/DasIch/argvard) - Commandr (https://github.com/tellapart/commandr https://github.com/tellapart/commandr) - Argtools (https://pypi.python.org/pypi/argtools/0.1.2 https://pypi.python.org/pypi/argtools/0.1.2) - Plac (https://pypi.python.org/pypi/plac https://pypi.python.org/pypi/plac)
- lookACamel 12y agoClime (https://github.com/moskytw/clime https://github.com/moskytw/clime)
- ptman 12y agocliapp ( http://git.liw.fi/cgi-bin/cgit/cgit.cgi/cliapp/ http://git.liw.fi/cgi-bin/cgit/cgit.cgi/cliapp/ )
- mahmoudimus 12y agohttps://pythonhosted.org/pyCLI/# https://pythonhosted.org/pyCLI/#
- frodopwns 12y agouser@uweb1:/$ pip install click Downloading/unpacking click Could not find any downloads that satisfy the requirement click No distributions at all found for click
- gr3yh47 12y agothe name is a bit oxymoronic