Your all-in-one for beautiful, prod-ready CLIs
Project description
🦄 clypi
Type-safe Python CLI prompts with validations, retries, custom messages, etc.
Examples
Check out the examples in ./examples! You can run them locally with:
uv run --all-extras -m examples.cli
uv run --all-extras -m examples.colors
uv run --all-extras -m examples.spinner
uv run --all-extras -m examples.prompts
CLI
# examples/basic_cli.py
from clypi import Command
class Lint(Command):
files: tuple[str, ...]
async def run(self):
print(f"Linting {', '.join(self.files)}")
class MyCli(Command):
subcommand: Lint | None = None
verbose: bool = False
async def run(self):
print(f"Running the main command with {self.verbose}")
if __name__ == "__main__":
cli: MyCli = MyCli.parse()
cli.start()
uv run -m examples.basic_cli -h (Main help page)
uv run -m examples.basic_cli lint (Subcommand help page)
uv run -m examples.basic_cli (Normal run)
uv run -m examples.basic_cli lint (Missing args error)
uv run -m examples.basic_cli lin (Typo)
❓ Prompting
First, you'll need to import the clypi module:
import clypi
answer = clypi.prompt("Are you going to use clypi?", default=True, parser=bool)
🌈 Colors
# demo.py
import clypi
# Style text
print(clypi.style("This is blue", fg="blue"), "and", clypi.style("this is red", fg="red"))
# Print with colors directly
clypi.print("Some colorful text", fg="green", reverse=True, bold=True, italic=True)
# Store a styler and reuse it
wrong = clypi.styler(fg="red", strikethrough=True)
print("The old version said", wrong("Pluto was a planet"))
print("The old version said", wrong("the Earth was flat"))
uv run demo.py
uv run -m examples.colors
🌀 Spinners
# demo.py
import asyncio
from clypi import Spinner
async def main():
async with Spinner("Downloading assets") as s:
for i in range(1, 6):
await asyncio.sleep(0.5)
s.title = f"Downloading assets [{i}/5]"
asyncio.run(main())
uv run demo.py
uv run -m examples.spinner
🐍 Type-checking
This library is fully type-checked. This means that all types will be correctly inferred from the arguments you pass in.
In this example your editor will correctly infer the type:
hours = clypi.prompt(
"How many hours are there in a year?",
parser=lambda x: float(x) if x < 24 else timedelta(days=x),
)
reveal_type(hours) # Type of "res" is "float | timedelta"
Why do I care?
Type checking will help you catch issues way earlier in the development cycle. It will also provide nice autocomplete features in your editor that will make you faster .
Integrations
Parsers (v6e, pydantic, etc.)
CLIPy can be integrated with many parsers. The default recommended parser is v6e, which is automatically used if installed in your local environment to parse types more accurately. If you wish you specify any parser (from v6e or elsewhere) manually, you can do so quite easily:
CLI
import v6e
from clypi import Command, config
class MyCli(Command):
files: list[Path] = config(parser=v6e.path().exists().list())
async def run(self):
files = [f.as_posix() for f in self.files]
print(f"Linting {', '.join(files)}")
if __name__ == "__main__":
cli: MyCli = MyCli.parse()
cli.start()
Prompting
import v6e
hours = clypi.prompt(
"How many hours are there in a year?",
parser=v6e.float().lte(24).union(v6e.timedelta()),
)
reveal_type(hours) # Type of "res" is "float | timedelta"
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clypi-0.1.4.tar.gz.
File metadata
- Download URL: clypi-0.1.4.tar.gz
- Upload date:
- Size: 42.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a89fa711d8026a5e9753bbb5a3c57768a7b88ce7e1c4c7beb089c55964030c3b
|
|
| MD5 |
8f1eff48872323fd526776f38a33e8ce
|
|
| BLAKE2b-256 |
132bb9d64b4b5561b1e5e81ef798cead8ae77b7aa8821e4e2411a4c5d5cbe949
|
Provenance
The following attestation bundles were made for clypi-0.1.4.tar.gz:
Publisher:
release.yml on danimelchor/clypi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clypi-0.1.4.tar.gz -
Subject digest:
a89fa711d8026a5e9753bbb5a3c57768a7b88ce7e1c4c7beb089c55964030c3b - Sigstore transparency entry: 176687760
- Sigstore integration time:
-
Permalink:
danimelchor/clypi@b2434a13a783c030c73501385920863f760eca71 -
Branch / Tag:
refs/tags/0.1.4 - Owner: https://github.com/danimelchor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b2434a13a783c030c73501385920863f760eca71 -
Trigger Event:
push
-
Statement type:
File details
Details for the file clypi-0.1.4-py3-none-any.whl.
File metadata
- Download URL: clypi-0.1.4-py3-none-any.whl
- Upload date:
- Size: 23.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aac9d6e865b6bc4559ca8e7a8e6ba8365f66248c603f60624466c64436217f19
|
|
| MD5 |
6980badb372e08b87b0e1190eee45c3c
|
|
| BLAKE2b-256 |
5b21674c00f4a62ef75046cf15aabcfd5141e04401ed76ab5fd16273a3417835
|
Provenance
The following attestation bundles were made for clypi-0.1.4-py3-none-any.whl:
Publisher:
release.yml on danimelchor/clypi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clypi-0.1.4-py3-none-any.whl -
Subject digest:
aac9d6e865b6bc4559ca8e7a8e6ba8365f66248c603f60624466c64436217f19 - Sigstore transparency entry: 176687768
- Sigstore integration time:
-
Permalink:
danimelchor/clypi@b2434a13a783c030c73501385920863f760eca71 -
Branch / Tag:
refs/tags/0.1.4 - Owner: https://github.com/danimelchor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b2434a13a783c030c73501385920863f760eca71 -
Trigger Event:
push
-
Statement type: