Building CLI Applications with Pydantic-settings
AI TL;DR
Using pydantic-settings, you can easily create type-safe and maintainable CLI applications. Instead of argparse, you can use class-based settings similar to pydantic, with support for reading environment variables and CLI arguments. The latest version supports parsing CLI arguments, making it easy to set up aliases, default values, and type hint completion. Subcommand implementation is also straightforward, making it easy to build complex CLI tools.
About pydantic-settings
pydantic-settings is well known as a library for loading settings from environment variables and dotenv files.
I used to think that pydantic's own functionality was sufficient for that, but recently a feature was added to load settings from CLI arguments. By the way, Azure Key Vault is supported, but AWS Systems Manager Parameter Store is not for some reason (as of October 2024). There is an Issue for it, so it may be supported eventually.
Python's built-in command-line argument parser argparse has issues such as difficulty specifying types and the need to double-define the Namespace. It's fine for throwaway scripts, but since type completion doesn't work, building larger CLI applications becomes somewhat tedious.
With pydantic-settings, you just write classes similar to pydantic, and the CLI argument parser is ready. Type specification and default value settings are easy, and type hints work well, providing comfortable development with autocompletion.
There are several other libraries that wrap argparse using pydantic, but using pydantic-settings, which is practically official, is advantageous in terms of maintenance and support. Also, all argparse features except groups are available, so the necessary functionality is essentially covered.
Install
The specification differs slightly between versions, so we specify version 2.6.0 here. Please refer to the documentation for the basics.
Usage
As shown below, simple CLI applications can be implemented by essentially just writing a pydantic class. Literals and enums can also be used.
By using docstrings and Field descriptions, you can customize help messages.
"simple.py"
This script works as follows. You can see that the help message is properly customized.
Execution looks like this. You get a properly typed pydantic object.
Subcommand
Subcommands can also be implemented without issues. By specifying CliSubCommand as a type annotation, you can define subcommands.
For example, let's build a git-like CLI.
Using get_subcommand
Basically, you branch based on the type obtained from get_subcommand. Since everything can be written manually, I personally find this approach more flexible.
"subcommand.py"
Using CliApp
CliApp automatically executes the cli_cmd method of each class. It also recursively executes subcommands.
However, passing parent class parameters down is cumbersome with this approach, so I personally think get_subcommand is fine.
When that's not needed, this approach is convenient.
"subcommand_app.py"
Conclusion
The CLI portion of pydantic-settings is under active development with frequent feature additions, and it will likely become even more user-friendly in the future. Since it is updated quite frequently, checking the latest documentation may reveal new capabilities.