[HN Gopher] Docopt ___________________________________________________________________ Docopt Author : tosh Score : 58 points Date : 2021-12-31 14:14 UTC (8 hours ago) (HTM) web link (docopt.org) (TXT) w3m dump (docopt.org) | kortex wrote: | I've tried just about every python cli parser out there: | argparse, click, Cleo, docopt, fire, hydra, typer, a few others. | Nothing has been a slam dunk for me the way Clap for rust or | cobra for go have been. But I've found a good enough system. | | My criteria are: well supported, composable, sub commands, | reusable options, sane stack traces. | | My current pattern: Cleo plus pydantic. I can create a module of | commonly used flags and options that I can share among commands. | Commands are first class objects. I can use them as entry points. | I can readily parse the options into a static structure with | defaults read from env or a file using pydantic. This is feed to | runner/API functions, with minimal logic in the command class | itself. The one thing that is lacking is I wish I could define | pydantic models that double as commands. That is a pretty | specific nit to pick. | | Overall I love it. Poetry runs on it so I think it's got a long | support life. It's beautiful. Easy to use. Just the right amount | of opinionated for me. Supports auto complete. Built in commonly | used flags like version, quiet, and verbose levels. | | I find click and any of the decorator based systems super obtuse | and difficult to compose. They add tons of noise to stack traces. | | Docopt is way too string based. I like static types. | | Argparse is... surprisingly not bad. The main drawback is reuse | is not very easy and it's hard to write composable structures. | epage wrote: | It seems like docopt was trendy for a while which always | surprised me. The idea of specifying your CLI in an incompletely | defined DSL embedded in a string always confused me both because | of the brittleness and because there is stuff you just can't | express (like types). | | In Python, I was always skeptical of click which later took the | attention though I think using StructOpt [0] in Rust has cured me | of that to a degree though I much prefer field attributes over | stacking function attributes per parameter (or Typer's form of | parameter attributes). I'd probably still stick with argparse | anyways because most of my Python scripts are built without | dependencies (weird build systems or being one step above bash | scripts). | | [0] https://docs.rs/structopt/latest/structopt/ | smitty1e wrote: | Speaking of Click: | | "Docopt, and many tools like it, are cool in how they work, but | very few of these tools deal with nesting of commands and | composability in a way like Click. To the best of the | developer's knowledge, Click is the first Python library that | aims to create a level of composability of applications that | goes beyond what the system itself supports. | | Docopt, for instance, acts by parsing your help pages and then | parsing according to those rules. The side effect of this is | that docopt is quite rigid in how it handles the command line | interface. The upside of docopt is that it gives you strong | control over your help page; the downside is that due to this | it cannot rewrap your output for the current terminal width, | and it makes translations hard. 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. | | Most of all, however, it makes composability hard. While docopt | does support dispatching to subcommands, it, for instance, does | not directly support any kind of automatic subcommand | enumeration based on what's available or it does not enforce | subcommands to work in a consistent way." | | https://click.palletsprojects.com/en/8.0.x/why/#why-not-doco... | cb321 wrote: | I think plac and argh in the Python space pre-dated Click by | a long time and had many similar features. I'm not sure if | they had everything the Click author exactly wanted, but they | do seem like strong prior related work. | michaelcampbell wrote: | > Most of all, however, it makes composability hard. | | I see this argument a lot as if it's self evident. Using X | makes Y hard. Ok, what if you don't need Y? | dragonwriter wrote: | > Using X makes Y hard. Ok, what if you don't need Y? | | Then knock yourself out using X. It's an argument about the | purpose of the alternative and what it is intended to be | useful for. Assuming that it is valid, it tells you both | for what purposes you might want to use the alternative and | for what purposes you might not want to bother. | | Z improves on X for Y is fairly explicitly not an argument | that Z is superior to X for all purposes. | cb321 wrote: | If the PL you are using already has named parameters with | defaults then you can roll a CLI on top of it with a better | spcified "spec" language (the PL itself) and with less work. | There are a few Python packages for this and | https://github.com/c-blake/cligen (which lets you add a CLI to an | existing API with just one line of code). | | This is theoretically even possible for C++ with some kind of | compile-time reflection API, but the way the C preprocessor works | probably makes it hard to preserve structured comments for | automatic documentation extraction. It was quite easy to do in | Nim. | ris wrote: | Please Just Say No. | | Docopt is the sort of thing that seems like it would work | wonderfully but you'd be surprised how quickly you end up running | into a situation that is ambiguous or just impossible to | represent using docopt. On the other hand, I never really found | that argparse-specified interfaces were significantly more | verbose to set up. | michaelcampbell wrote: | I've used it, and it's... fine, I guess. I ended up using | something else but it was kind of nifty. | pythux wrote: | I used it a lot and it usually works great. Of course there are | corner cases but if you don't need to handle them in most cases | I don't think it means you should never use the library in the | first place. | shrimpx wrote: | I've used docopt a ton for core CLI tooling at my last company. | IMO its shortcomings outweigh the benefits by a long margin, | compared to tools like argparse which make it super hard to | understand what the full UI of a tool is. That said, my company | did start transitioning to Click because of its | nesting/subcommand abilities. I would probably choose Click for a | new project, but I do think docopt is still the best for speed of | understanding the total interface of a tool. You just read the | `__doc__` straight up. | junon wrote: | Used this before for a few languages and assuming you can | incorporate it into your build system it's actually quite | pleasant to use. | | The problem is, shoe-horning it into your project can be a huge | burden. It's why I left it in my toolbox as more of a toy. | hprotagonist wrote: | These days i use typer (https://typer.tiangolo.com/), but docopt | remains a fan favorite of mine for being just so darn cute. | | it's a shame that the last i checked, there wasn't really a | formal grammar for it and so doing a lot of the modern | conveniences i like[0] is either hard or impossible, but the | idea's still charming. | | [0]: i want things like "ensure this is a path and it's a file | and it exists and it's nonzero size and give it back to me as a | `pathlib.Path` please" or "this argument must be an integer | between 10 and 5002", etc. | formerly_proven wrote: | rST somehow ended up with a (strict) parser for more or less | this: | https://docutils.sourceforge.io/docs/ref/rst/restructuredtex... | dbrgn wrote: | I like Docopt for quick scripts, used it both in Python and Rust | projects. It is quite unflexible though. | | The Rust Docopt implementation1 was deprecated this year, which | is probably good because clap v32 is so awesome. In a project of | mine (tealdeer), I noticed that docopt.rs was responsible for the | _huge_ majority of CPU instructions when running the binary: | https://github.com/dbrgn/tealdeer/issues/106#issuecomment-59... I | then switched3 to clap and shaved off almost a megabyte from the | release binary4. Performance improved as well, time required for | rendering a tldr page went down from ~15.9 ms to ~12.4 ms5. With | the migration, we also managed to reduce a lot of custom | validation logic and move this logic into the derive macro | attributes. | | 1 https://github.com/docopt/docopt.rs | | 2 https://github.com/clap-rs/clap | | 3 https://github.com/dbrgn/tealdeer/pull/108 | | 4 https://github.com/dbrgn/tealdeer/pull/108#issuecomment-9448... | | 5 https://github.com/dbrgn/tealdeer/pull/108#issuecomment-9448... | guitarbill wrote: | I agree that clap v3 (with it's derive capabilities basically | incorporating structopt) is awesome. But it's still pretty | heavyweight, although you can make it a bit more lightweight by | turning off some features. In some cases, I actually put the | CLI args in a separate crate, so that changing the program | doesn't involve rebuilding the CLI arg structures. As a bonus, | it makes changes to the CLI much more obvious in code review. | epage wrote: | Now that we have clap 3.0 released, trimming the fat is going | to be a focus. | dbrgn wrote: | Hmm, putting them in a subcrate / separate compilation unit | is pretty smart. I can imagine that quite a chunk of the | compilation time goes into the proc macros :) ___________________________________________________________________ (page generated 2021-12-31 23:01 UTC)