Skip to content

Commit 1a1c4a6

Browse files
authored
Merge pull request #49 from bckohan/v1.1.x
V1.1.x
2 parents 1381b7b + 0856f54 commit 1a1c4a6

15 files changed

+566
-651
lines changed

.github/workflows/lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
mypy django_typer
5555
poetry check
5656
pip check
57-
python -m readme_renderer ./README.rst -o /tmp/README.html
57+
python -m readme_renderer ./README.md -o /tmp/README.html
5858
cd ./doc
5959
doc8 --ignore-path build --max-line-length 100
6060
echo "$(poetry env info --path)/bin" >> $GITHUB_PATH

CONTRIBUTING.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ certain errors or warnings where justified is acceptable:
6767
pyright
6868
poetry check
6969
poetry run pip check
70-
poetry run python -m readme_renderer ./README.rst
70+
poetry run python -m readme_renderer ./README.md
7171
7272
7373
Running Tests

README.md

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# django-typer
2+
3+
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
[![PyPI version](https://badge.fury.io/py/django-typer.svg)](https://pypi.python.org/pypi/django-typer/)
6+
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/django-typer.svg)](https://pypi.python.org/pypi/django-typer/)
7+
[![PyPI djversions](https://img.shields.io/pypi/djversions/django-typer.svg)](https://pypi.org/project/django-typer/)
8+
[![PyPI status](https://img.shields.io/pypi/status/django-typer.svg)](https://pypi.python.org/pypi/django-typer)
9+
[![Documentation Status](https://readthedocs.org/projects/django-typer/badge/?version=latest)](http://django-typer.readthedocs.io/?badge=latest/)
10+
[![Code Cov](https://codecov.io/gh/bckohan/django-typer/branch/main/graph/badge.svg?token=0IZOKN2DYL)](https://codecov.io/gh/bckohan/django-typer)
11+
[![Test Status](https://github.com/bckohan/django-typer/workflows/test/badge.svg)](https://github.com/bckohan/django-typer/actions/workflows/test.yml)
12+
[![Lint Status](https://github.com/bckohan/django-typer/workflows/lint/badge.svg)](https://github.com/bckohan/django-typer/actions/workflows/lint.yml)
13+
[![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
14+
15+
Use [Typer](https://typer.tiangolo.com/) to define the CLI for your [Django](https://www.djangoproject.com/) management commands. Provides a TyperCommand class that inherits from [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand) and allows typer-style annotated parameter types. All of the BaseCommand functionality is preserved, so that TyperCommand can be a drop-in replacement.
16+
17+
**django-typer makes it easy to:**
18+
19+
- Define your command CLI interface in a clear, DRY, and safe way using type hints.
20+
- Create subcommand and group command hierarchies.
21+
- Use the full power of Typer's parameter types to validate and parse command line inputs.
22+
- Create beautiful and information dense help outputs.
23+
- Configure the rendering of exception stack traces using rich.
24+
- [Install shell tab-completion support](https://django-typer.readthedocs.io/en/latest/shell_completion.html) for TyperCommands and normal Django commands for [bash](https://www.gnu.org/software/bash/), [zsh](https://www.zsh.org/), [fish](https://fishshell.com/), and [powershell](https://learn.microsoft.com/en-us/powershell/scripting/overview).
25+
- [Create custom and portable shell tab-completions for your CLI parameters.](https://django-typer.readthedocs.io/en/latest/shell_completion.html#defining-custom-completions)
26+
- Refactor existing management commands into TyperCommands because TyperCommand is interface compatible with BaseCommand.
27+
28+
Please refer to the [full documentation](https://django-typer.readthedocs.io/) for more information.
29+
30+
![django-typer example](https://raw.githubusercontent.com/bckohan/django-typer/main/doc/source/_static/img/closepoll_example.gif)
31+
32+
## Installation
33+
34+
1. Clone django-typer from GitHub or install a release off [PyPI](https://pypi.org/project/django-typer/):
35+
36+
```bash
37+
pip install django-typer
38+
```
39+
40+
[rich](https://rich.readthedocs.io/en/latest/) is a powerful library for rich text and beautiful formatting in the terminal. It is not required but highly recommended for the best experience:
41+
42+
```bash
43+
pip install "django-typer[rich]"
44+
```
45+
46+
2. Add `django_typer` to your `INSTALLED_APPS` setting:
47+
48+
```python
49+
INSTALLED_APPS = [
50+
...
51+
'django_typer',
52+
]
53+
```
54+
55+
*You only need to install django_typer as an app if you want to use the shell completion command to enable tab-completion or if you would like django-typer to install [rich traceback rendering](https://django-typer.readthedocs.io/en/latest/howto.html#configure-rich-stack-traces) for you - which it does by default if rich is also installed.*
56+
57+
## Basic Example
58+
59+
For example, TyperCommands can be a very simple drop-in replacement for BaseCommands. All of the documented features of [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand) work!
60+
61+
```python
62+
from django_typer import TyperCommand
63+
64+
class Command(TyperCommand):
65+
def handle(self, arg1: str, arg2: str, arg3: float = 0.5, arg4: int = 1):
66+
"""
67+
A basic command that uses Typer
68+
"""
69+
```
70+
71+
![Basic Example](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/basic.svg)
72+
73+
## Multiple Subcommands Example
74+
75+
76+
77+
Commands with multiple subcommands can be defined:
78+
79+
```python
80+
import typing as t
81+
82+
from django.utils.translation import gettext_lazy as _
83+
from typer import Argument
84+
85+
from django_typer import TyperCommand, command
86+
87+
88+
class Command(TyperCommand):
89+
"""
90+
A command that defines subcommands.
91+
"""
92+
93+
@command()
94+
def create(
95+
self,
96+
name: t.Annotated[str, Argument(help=_("The name of the object to create."))],
97+
):
98+
"""
99+
Create an object.
100+
"""
101+
102+
@command()
103+
def delete(
104+
self, id: t.Annotated[int, Argument(help=_("The id of the object to delete."))]
105+
):
106+
"""
107+
Delete an object.
108+
"""
109+
110+
```
111+
112+
![Multiple Subcommands Example](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/multi.svg)
113+
![Multiple Subcommands Example - create](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/multi_create.svg)
114+
![Multiple Subcommands Example - delete](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/multi_delete.svg)
115+
116+
## Grouping and Hierarchies Example
117+
118+
More complex groups and subcommand hierarchies can be defined. For example, this command defines a group of commands called math, with subcommands divide and multiply. The group has a common initializer that optionally sets a float precision value. We would invoke this command like so:
119+
120+
```bash
121+
./manage.py hierarchy math --precision 5 divide 10 2.1
122+
./manage.py hierarchy math multiply 10 2
123+
```
124+
125+
```python
126+
import typing as t
127+
from functools import reduce
128+
129+
from django.utils.translation import gettext_lazy as _
130+
from typer import Argument, Option
131+
132+
from django_typer import TyperCommand, group
133+
134+
135+
class Command(TyperCommand):
136+
137+
help = _("A more complex command that defines a hierarchy of subcommands.")
138+
139+
precision = 2
140+
141+
@group(help=_("Do some math at the given precision."))
142+
def math(
143+
self,
144+
precision: t.Annotated[
145+
int, Option(help=_("The number of decimal places to output."))
146+
] = precision,
147+
):
148+
self.precision = precision
149+
150+
@math.command(help=_("Multiply the given numbers."))
151+
def multiply(
152+
self,
153+
numbers: t.Annotated[
154+
t.List[float], Argument(help=_("The numbers to multiply"))
155+
],
156+
):
157+
return f"{reduce(lambda x, y: x * y, [1, *numbers]):.{self.precision}f}"
158+
159+
@math.command()
160+
def divide(
161+
self,
162+
numerator: t.Annotated[float, Argument(help=_("The numerator"))],
163+
denominator: t.Annotated[float, Argument(help=_("The denominator"))],
164+
floor: t.Annotated[bool, Option(help=_("Use floor division"))] = False,
165+
):
166+
"""
167+
Divide the given numbers.
168+
"""
169+
if floor:
170+
return str(numerator // denominator)
171+
return f"{numerator / denominator:.{self.precision}f}"
172+
173+
```
174+
175+
![Grouping and Hierarchies Example](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/hierarchy.svg)
176+
![Grouping and Hierarchies Example - math](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/hierarchy_math.svg)
177+
![Grouping and Hierarchies Example - math multiply](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/hierarchy_math_multiply.svg)
178+
![Grouping and Hierarchies Example - math divide](https://raw.githubusercontent.com/bckohan/django-typer/main/django_typer/examples/helps/hierarchy_math_divide.svg)

0 commit comments

Comments
 (0)