Conversation
docopt to click
|
I personally like this implementation better. You have to repeat yourself a little because |
dav3r
left a comment
There was a problem hiding this comment.
I think both typer and click seem fine for our needs. I asked Google about it and here's what it came back with:
Pick Typer if: You want a modern developer experience with excellent autocompletion and less boilerplate. It is ideal if you are already using FastAPI, as it shares the same design philosophy.
Pick Click if: You need a proven, stable tool with maximum control and minimal dependencies. It is often preferred for very large, complex CLI structures where explicit control over every parameter is necessary.
Hybrid Approach: Because Typer is built on Click, you can use Typer for your main interface but drop down into Click for advanced features that Typer might not yet support.
That being said, I have no major preference here and will gladly go with whichever one our team feels more strongly about.
There was a problem hiding this comment.
Pull request overview
This PR migrates the project CLI from docopt/schema to click, updating the entrypoints and tests accordingly.
Changes:
- Replaced docopt-based parsing/validation with a
clickcommand (setup_logging_and_divide) and parameter validation callbacks. - Updated tests to use
click.testing.CliRunnerand adjusted expectations for Click-style exit codes/output. - Updated packaging metadata: dependencies, console script target, and pre-commit mypy deps.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_example.py | Switches CLI tests to invoke the Click command via CliRunner and updates assertions. |
| src/example/example.py | Replaces docopt CLI with Click command/options/arguments and adds Rich logging handler + callbacks. |
| src/example/_version.py | Bumps project version for the prerelease. |
| src/example/main.py | Updates module entrypoint to run the Click command. |
| src/example/init.py | Updates exported API names to match renamed functions/command. |
| pyproject.toml | Swaps dependencies and changes the console script entrypoint to the Click command. |
| .pre-commit-config.yaml | Removes mypy stub dependency associated with docopt. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e1e3049 to
56584a2
Compare
docopt hasn't been updated in years and is still built using setup.py. click is a more modern CLI library. For more information see: - https://click.palletsprojects.com/en/stable/ - https://github.com/pallets/click
Also update the version tests to deal with the version output that click generates by default.
This is a little cleaner and results in clightly more readable code than patching argv.
Also go ahead and export the setup_logging_and_divide function as part of the module.
Co-authored-by: dav3r <david.redmin@gwe.cisa.dhs.gov>
This will allow the feature gate to remain valid across major versions. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
The new docstring describes more fully what the function does. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This is what docopt used to do, so to avoid an unexpected change we should do the same. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
capsys is no longer used in test_stdout_version after switching to CliRunner. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This is possible now that `--version` returns only the version string.
This gets rid of the following warning from our flake8 pre-commit hook: C408 Unnecessary list call - rewrite as a literal
This gets rid of the following warning from our flake8 pre-commit hook: C408 Unnecessary dict call - rewrite as a literal.
This gets rid of the following error from our flake8 pre-commit hook: B950 line too long (94 > 80 characters)
168013e to
bf8d49d
Compare
These dependencies will be commonly used with this type of repo, so we may as well handle them at the skeleton level.
mcdonnnj
left a comment
There was a problem hiding this comment.
So I have a more general issue after reviewing this PR and looking up more about Click. I know that it is a popular options, however I am not a fan of the forced decorator approach and how functions get wrapped to start. The use of either the .callback() attribute or using invoke() make reusability of functions difficult. You are forced to either use the above methods or create CLI command wrapper functions that in turn access the real functionality.
I much prefer the ability to use dataclasses or dataclass-like objects (Pydantic models/dataclasses for example) to define command behavior using Python type hints. There are a number of options out there so I'm not trying to sell a particular one, but as an example I migrated the library to cappa in the improvement/switch_to_cappa_from_docopt branch just for an example of what that would look like. There are other options in a similar vein such as Clypi and tyro.
Those libraries are nicer but appear to mostly depend on the work of a single developer. One advantage of That said, I think @cisagov/vm-dev should come to a consensus and we should go with whatever is decided. |
I agree with @jsf9k that a widely-used library like |
|
I think I would like to see some of the typing features the other libraries support, and hope they appear in the future. |

🗣 Description
This pull request switches from
docopttoclickfor our CLI argument-parsing needs.💭 Motivation and context
I noticed that installing
docoptgenerates warnings because it still uses asetup.pyfile versus apyproject.tomlfile. Investigating further, I found thatdocopthasn't seen any updates since 2014. I figured now would be a good time to start looking at alternatives.The main two alternatives right now are
clickandtyper. The former is a bit more verbose, whereas the latter is a bit more opinionated but also more Pythonic.typerusesclickunder the hood and leverages type hints to do some work for you. Both can generate tab completion for various shells.See also #175 for the
typerimplementation. We can choose which one we like better.🧪 Testing
All automated tests pass.
✅ Pre-approval checklist
bump_versionscript if this repository is versioned and the changes in this PR warrant a version bump.✅ Pre-merge checklist
✅ Post-merge checklist