Security News
38% of CISOs Fear They’re Not Moving Fast Enough on AI
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Build powerful CLIs with simple idiomatic Python, driven by type hints. Not all arguments are bad.
Not all arguments are bad.
Build powerful CLIs with simple idiomatic Python, driven by type hints.
About · Features · Installation · Build status · Documentation · Related projects · Contributing · Licensing
Designing a good CLI can quickly spiral into chaos without the help of an intuitive CLI framework.
Feud builds on Click for argument parsing, along with Pydantic for typing, to make CLI building a breeze.
Click is often considered the defacto command-line building utility for Python –
offering far more functionality and better ease-of-use than the standard
library's argparse
.
Despite this, for even the simplest of CLIs, code written using Click can be
somewhat verbose and often requires frequently looking up documentation.
Consider the following example command for serving local files on a HTTP server.
In red is a typical Click implementation, and in green is the Feud equivalent.
Example: Command for running a HTTP web server. |
|
Click here to view the generated help screen.
Help screen for the
|
Click here to see usage examples.
|
The core design principle behind Feud is to make it as easy as possible for even beginner Python developers to quickly create sophisticated CLIs.
The above function is written in idiomatic Python, adhering to language standards and using basic core language features such as type hints and docstrings to declare the relevant information about the CLI, but relying on Feud to carry out the heavy lifting of converting these language elements into a fully-fledged CLI.
While a single command is often all that you need, Feud makes it straightforward to logically group together related commands into a group represented by a class with commands defined within it.
Example: Commands for creating, deleting and listing blog posts. |
|
Click here to view the generated help screen.
Help screen for the
Help screen for the
|
Click here to see usage examples.
|
Alternatively, if you already have some functions defined that you would like
to run as commands, you can simply provide them to feud.run
and it will
automatically generate and run a group with those commands.
# post.py
import feud
from datetime import date
def create_post(id: int, *, title: str, desc: str | None = None):
"""Create a blog post."""
def delete_posts(*ids: int):
"""Delete blog posts."""
def list_posts(*, between: tuple[date, date] | None = None):
"""View all blog posts, optionally filtering by date range."""
if __name__ == "__main__":
feud.run([create_post, delete_posts, list_posts])
You can also use a dict
to rename the generated commands:
feud.run({"create": create_post, "delete": delete_posts, "list": list_posts})
For more complex applications, you can also nest commands in sub-groups:
feud.run({"list": list_posts, "modify": [create_post, delete_posts]})
If commands are defined in another module, you can also run the module directly and Feud will pick up all runnable objects:
import post
feud.run(post)
You can even call feud.run()
without providing any object, and it will
automatically discover all runnable objects in the current module.
As you can see, building a CLI using Feud does not require learning many new magic methods or a domain-specific language – you can just use the simple Python you know and ❤️!
Groups can be registered as sub-groups under other groups. This is a common pattern in CLIs, allowing for interfaces packed with lots of functionality, but still organized in a sensible way.
Example: CLI with the following structure for running and managing a blog.
|
|
Click here to view the generated help screen.
Help screen for the
Help screen for the
Help screen for the
Help screen for the
|
Click here to see usage examples.
|
Feud is powered by Pydantic – a validation library with extensive support for many data types, including:
pydantic-extra-types
is
an optional dependency offering additional types such as country names,
payment card numbers, phone numbers, colours, latitude/longitude and more.
Custom annotated types with user-defined validation functions can also be defined with Pydantic.
Example: Command for generating audio samples from text prompts using a machine learning model, and storing produced audio files in an output directory.
|
|
Click here to view the generated help screen.
Help screen for the
|
Click here to see usage examples.
If we run the script without prompts, we get an error that at least one prompt must be provided.
If we provide a prompt longer than 12 characters, we also get an error.
|
By relying on Pydantic to handle the hard work of validation, we can contain all of the required CLI constraints in a simple function signature, leaving you to focus on the important part – implementing your commands.
While designed to be simpler than Click, this comes with the trade-off that Feud is also more opinionated than Click and only directly implements a subset of its functionality.
However, Feud was designed to allow for Click to seamlessly slot in whenever manual overrides are necessary.
Example: Use |
|
Click here to view the generated help screen.
Help screen for the
|
Click here to see usage examples.
|
As Feud commands and groups compile to Click objects under the hood, this opens up the ability to interact with all integrations that Click supports.
feud.Group
into a click.Group
, use the .compile()
method defined on feud.Group
.@feud.command
decorator converts a function into a click.Command
.Once you have a click.Command
or click.Group
produced by Feud,
it is possible to use it with Click extensions such as:
click-man
: Automate generation of manual pages for Click applications.click-completion
: Add or enhance bash
, fish
, zsh
and powershell
completion in Click.sphinx-click
: A Sphinx plugin to automatically document Click-based applications.For more examples of Click extensions, see the click-contrib
project.
You can install Feud using pip
.
The latest stable version of Feud can be installed with the following command.
pip install "feud[all]"
This installs Feud with the optional dependencies:
rich-click
(can install individually with pip install "feud[rich]"
)pydantic-extra-types
(can install individually with pip install "feud[extra-types]"
)email-validator
(can install individually with pip install "feud[email]"
)To install Feud without any optional dependencies, simply run pip install feud
.
Below is a comparison of Feud with and without rich-click
.
With Rich-formatted output | Without Rich-formatted output |
---|---|
master | dev |
---|---|
Feud either relies heavily on, or was inspired by the following packages. It would be greatly appreciated if you also supported the below maintainers and the work they have done that Feud has built upon.
Project | Description |
---|---|
by @pallets |
Feud is essentially a wrapper around Click that takes classes and functions with type hints and intelligently 'compiles' them into a ready-to-use Click generated CLI. |
by @ewels |
A shim around Click that renders help output nicely using Rich. |
Pydantic is a validation package that makes it easy to declaratively validate input data based on type hints. The package offers support for common standard library types, plus more complex types which can also be used as type hints in Feud commands for input validation. | |
by @tiangolo |
Typer shares a similar ideology to Feud, in that building CLIs should be simple and not require learning new functions or constantly referring to library documentation. Typer is also based on Click. Typer is a more complete library for building CLIs overall, but currently lacks support for more complex types such as those offered by Pydantic. |
by @rails |
Though not a Python package, the highly object-oriented design of Thor (a CLI
building package in Ruby) – in particular the use of classes to define command
groups – greatly influenced the implementation of the |
All contributions to this repository are greatly appreciated. Contribution guidelines can be found here.
We're living in an imperfect world!
Feud is still in a test phase, likely with lots of bugs. Please leave feedback if you come across anything strange!
Feud is released under the MIT license.
Feud © 2023, Edwin Onuonga - Released under the MIT license.
Authored and maintained by Edwin Onuonga.
FAQs
Build powerful CLIs with simple idiomatic Python, driven by type hints. Not all arguments are bad.
We found that feud demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Research
Security News
Socket researchers uncovered a backdoored typosquat of BoltDB in the Go ecosystem, exploiting Go Module Proxy caching to persist undetected for years.
Security News
Company News
Socket is joining TC54 to help develop standards for software supply chain security, contributing to the evolution of SBOMs, CycloneDX, and Package URL specifications.