django-typer


Namedjango-typer JSON
Version 2.3.0 PyPI version JSON
download
home_pagehttps://django-typer.readthedocs.io
SummaryUse Typer to define the CLI for your Django management commands.
upload_time2024-10-13 06:02:19
maintainerNone
docs_urlNone
authorBrian Kohan
requires_python<4.0,>=3.9
licenseMIT
keywords django cli management typer commands
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # django-typer


[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![PyPI version](https://badge.fury.io/py/django-typer.svg)](https://pypi.python.org/pypi/django-typer/)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/django-typer.svg)](https://pypi.python.org/pypi/django-typer/)
[![PyPI djversions](https://img.shields.io/pypi/djversions/django-typer.svg)](https://pypi.org/project/django-typer/)
[![PyPI status](https://img.shields.io/pypi/status/django-typer.svg)](https://pypi.python.org/pypi/django-typer)
[![Documentation Status](https://readthedocs.org/projects/django-typer/badge/?version=latest)](http://django-typer.readthedocs.io/?badge=latest/)
[![Code Cov](https://codecov.io/gh/django-commons/django-typer/branch/main/graph/badge.svg?token=0IZOKN2DYL)](https://codecov.io/gh/django-commons/django-typer)
[![Test Status](https://github.com/django-commons/django-typer/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/django-commons/django-typer/actions/workflows/test.yml?query=branch:main)
[![Lint Status](https://github.com/django-commons/django-typer/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/django-commons/django-typer/actions/workflows/lint.yml?query=branch:main)
[![Published on Django Packages](https://img.shields.io/badge/Published%20on-Django%20Packages-0c3c26)](https://djangopackages.org/packages/p/django-typer/)

Use static typing to define the CLI for your [Django](https://www.djangoproject.com/) management commands with [Typer](https://typer.tiangolo.com/). Optionally use the provided [TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) class that inherits from [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand). This class maps the [Typer](https://typer.tiangolo.com/) interface onto a class based interface that Django developers will be familiar with. All of the [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand) functionality is preserved, so that [TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) can be a drop in replacement.

**django-typer makes it easy to:**

   * Define your command CLI interface in a clear, DRY and safe way using type hints
   * Create subcommands and hierarchical groups of commands.
   * Use the full power of [Typer](https://typer.tiangolo.com/)'s parameter types to validate and parse command line inputs.
   * Create beautiful and information dense help outputs.
   * Configure the rendering of exception stack traces using [rich](https://rich.readthedocs.io/en/latest/).
   * [Install shell tab-completion support](https://django-typer.readthedocs.io/en/latest/shell_completion.html) 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).
   * [Create custom and portable shell tab-completions for your CLI parameters.](https://django-typer.readthedocs.io/en/latest/shell_completion.html#defining-custom-completions)
   * Port existing commands ([TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) is interface compatible with [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand)).
   * Use either a Django-style class-based interface or the Typer-style interface to define commands.
   * Add plugins to upstream commands.

Please refer to the [full documentation](https://django-typer.readthedocs.io/) for more information.

![django-typer example](https://raw.githubusercontent.com/django-commons/django-typer/main/doc/source/_static/img/closepoll_example.gif)

## 🚨 Deprecation Notice

**Imports from ``django_typer`` have been deprecated and will be removed in 3.0! Imports have moved to ``django_typer.management``:**

```python
   # old way
   from django_typer import TyperCommand, command, group, initialize, Typer

   # new way!
   from django_typer.management import TyperCommand, command, group, initialize, Typer
```

## Installation

1. Clone django-typer from GitHub or install a release off [PyPI](https://pypi.org/project/django-typer/):

   ```bash
   pip install django-typer
   ```

   [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:

   ```bash
   pip install "django-typer[rich]"
   ```

2. Optionally add `django_typer` to your `INSTALLED_APPS` setting:

   ```python
   INSTALLED_APPS = [
       ...
       'django_typer',
   ]
   ```

*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.*

## Basic Example

[TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) is a drop in extension to [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand). All of the documented features of [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand) work the same way!

```python
from django_typer.management import TyperCommand

class Command(TyperCommand):
    def handle(self, arg1: str, arg2: str, arg3: float = 0.5, arg4: int = 1):
        """
        A basic command that uses Typer
        """
```

Or, you may also use an interface identical to [Typer](https://typer.tiangolo.com/)'s. Simply import [Typer](https://typer.tiangolo.com/) from django_typer instead of typer.

```python
from django_typer.management import Typer

app = Typer()

@app.command()
def main(arg1: str, arg2: str, arg3: float = 0.5, arg4: int = 1):
   """
   A basic command that uses Typer
   """
```

![Basic Example](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/basic.svg)

## Multiple Subcommands Example



Commands with multiple subcommands can be defined:

```python
   import typing as t

   from django.utils.translation import gettext_lazy as _
   from typer import Argument

   from django_typer.management import TyperCommand, command


   class Command(TyperCommand):
      """
      A command that defines subcommands.
      """

      @command()
      def create(
         self,
         name: t.Annotated[str, Argument(help=_("The name of the object to create."))],
      ):
         """
         Create an object.
         """

      @command()
      def delete(
         self, id: t.Annotated[int, Argument(help=_("The id of the object to delete."))]
      ):
         """
         Delete an object.
         """

```

Or using the typer-style interface this could be written:

```python
from django_typer.management import Typer
import typing as t

from django.utils.translation import gettext_lazy as _
from typer import Argument

app = Typer(help="A command that defines subcommands.")

@app.command()
def create(
   name: t.Annotated[str, Argument(help=_("The name of the object to create."))],
):
   """
   Create an object.
   """

@app.command()
def delete(
   id: t.Annotated[int, Argument(help=_("The id of the object to delete."))]
):
   """
   Delete an object.
   """
```

![Multiple Subcommands Example](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/multi.svg)
![Multiple Subcommands Example - create](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/multi_create.svg)
![Multiple Subcommands Example - delete](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/multi_delete.svg)


## Grouping and Hierarchies Example

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:

```bash
./manage.py hierarchy math --precision 5 divide 10 2.1
./manage.py hierarchy math multiply 10 2
```

Using the class-based interface we could define the command like this:

```python
   import typing as t
   from functools import reduce

   from django.utils.translation import gettext_lazy as _
   from typer import Argument, Option

   from django_typer.management import TyperCommand, group


   class Command(TyperCommand):

      help = _("A more complex command that defines a hierarchy of subcommands.")

      precision = 2

      @group(help=_("Do some math at the given precision."))
      def math(
         self,
         precision: t.Annotated[
            int, Option(help=_("The number of decimal places to output."))
         ] = precision,
      ):
         self.precision = precision

      # helps can be passed to the decorators
      @math.command(help=_("Multiply the given numbers."))
      def multiply(
         self,
         numbers: t.Annotated[
            t.List[float], Argument(help=_("The numbers to multiply"))
         ],
      ):
         return f"{reduce(lambda x, y: x * y, [1, *numbers]):.{self.precision}f}"

      # or if no help is supplied to the decorators, the docstring if present
      # will be used!
      @math.command()
      def divide(
         self,
         numerator: t.Annotated[float, Argument(help=_("The numerator"))],
         denominator: t.Annotated[float, Argument(help=_("The denominator"))],
         floor: t.Annotated[bool, Option(help=_("Use floor division"))] = False,
      ):
         """
         Divide the given numbers.
         """
         if floor:
               return str(numerator // denominator)
         return f"{numerator / denominator:.{self.precision}f}"

```

The typer-style interface builds a [TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) class for us **that allows you to optionally accept the self argument in your commands.** We could define the above command using the typer interface like this:

```python

import typing as t
from functools import reduce

from django.utils.translation import gettext_lazy as _
from typer import Argument, Option

from django_typer.management import Typer


app = Typer(help=_("A more complex command that defines a hierarchy of subcommands."))


math_grp = Typer(help=_("Do some math at the given precision."))

app.add_typer(math_grp)

@math_grp.callback()
def math(
   self,
   precision: t.Annotated[
      int, Option(help=_("The number of decimal places to output."))
   ] = 2,
):
   self.precision = precision


@math_grp.command(help=_("Multiply the given numbers."))
def multiply(
   self,
   numbers: t.Annotated[
      t.List[float], Argument(help=_("The numbers to multiply"))
   ],
):
   return f"{reduce(lambda x, y: x * y, [1, *numbers]):.{self.precision}f}"

@math_grp.command()
def divide(
   self,
   numerator: t.Annotated[float, Argument(help=_("The numerator"))],
   denominator: t.Annotated[float, Argument(help=_("The denominator"))],
   floor: t.Annotated[bool, Option(help=_("Use floor division"))] = False,
):
   """
   Divide the given numbers.
   """
   if floor:
         return str(numerator // denominator)
   return f"{numerator / denominator:.{self.precision}f}"
```

![Grouping and Hierarchies Example](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy.svg)
![Grouping and Hierarchies Example - math](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy_math.svg)
![Grouping and Hierarchies Example - math multiply](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy_math_multiply.svg)
![Grouping and Hierarchies Example - math divide](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy_math_divide.svg)


            

Raw data

            {
    "_id": null,
    "home_page": "https://django-typer.readthedocs.io",
    "name": "django-typer",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.9",
    "maintainer_email": null,
    "keywords": "django, CLI, management, Typer, commands",
    "author": "Brian Kohan",
    "author_email": "bckohan@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/91/d3/dd993ae74426920a38643696a34bdf9a21ab265588b124c0b595968839b0/django_typer-2.3.0.tar.gz",
    "platform": null,
    "description": "# django-typer\n\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n[![PyPI version](https://badge.fury.io/py/django-typer.svg)](https://pypi.python.org/pypi/django-typer/)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/django-typer.svg)](https://pypi.python.org/pypi/django-typer/)\n[![PyPI djversions](https://img.shields.io/pypi/djversions/django-typer.svg)](https://pypi.org/project/django-typer/)\n[![PyPI status](https://img.shields.io/pypi/status/django-typer.svg)](https://pypi.python.org/pypi/django-typer)\n[![Documentation Status](https://readthedocs.org/projects/django-typer/badge/?version=latest)](http://django-typer.readthedocs.io/?badge=latest/)\n[![Code Cov](https://codecov.io/gh/django-commons/django-typer/branch/main/graph/badge.svg?token=0IZOKN2DYL)](https://codecov.io/gh/django-commons/django-typer)\n[![Test Status](https://github.com/django-commons/django-typer/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/django-commons/django-typer/actions/workflows/test.yml?query=branch:main)\n[![Lint Status](https://github.com/django-commons/django-typer/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/django-commons/django-typer/actions/workflows/lint.yml?query=branch:main)\n[![Published on Django Packages](https://img.shields.io/badge/Published%20on-Django%20Packages-0c3c26)](https://djangopackages.org/packages/p/django-typer/)\n\nUse static typing to define the CLI for your [Django](https://www.djangoproject.com/) management commands with [Typer](https://typer.tiangolo.com/). Optionally use the provided [TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) class that inherits from [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand). This class maps the [Typer](https://typer.tiangolo.com/) interface onto a class based interface that Django developers will be familiar with. All of the [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand) functionality is preserved, so that [TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) can be a drop in replacement.\n\n**django-typer makes it easy to:**\n\n   * Define your command CLI interface in a clear, DRY and safe way using type hints\n   * Create subcommands and hierarchical groups of commands.\n   * Use the full power of [Typer](https://typer.tiangolo.com/)'s parameter types to validate and parse command line inputs.\n   * Create beautiful and information dense help outputs.\n   * Configure the rendering of exception stack traces using [rich](https://rich.readthedocs.io/en/latest/).\n   * [Install shell tab-completion support](https://django-typer.readthedocs.io/en/latest/shell_completion.html) 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).\n   * [Create custom and portable shell tab-completions for your CLI parameters.](https://django-typer.readthedocs.io/en/latest/shell_completion.html#defining-custom-completions)\n   * Port existing commands ([TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) is interface compatible with [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand)).\n   * Use either a Django-style class-based interface or the Typer-style interface to define commands.\n   * Add plugins to upstream commands.\n\nPlease refer to the [full documentation](https://django-typer.readthedocs.io/) for more information.\n\n![django-typer example](https://raw.githubusercontent.com/django-commons/django-typer/main/doc/source/_static/img/closepoll_example.gif)\n\n## \ud83d\udea8 Deprecation Notice\n\n**Imports from ``django_typer`` have been deprecated and will be removed in 3.0! Imports have moved to ``django_typer.management``:**\n\n```python\n   # old way\n   from django_typer import TyperCommand, command, group, initialize, Typer\n\n   # new way!\n   from django_typer.management import TyperCommand, command, group, initialize, Typer\n```\n\n## Installation\n\n1. Clone django-typer from GitHub or install a release off [PyPI](https://pypi.org/project/django-typer/):\n\n   ```bash\n   pip install django-typer\n   ```\n\n   [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:\n\n   ```bash\n   pip install \"django-typer[rich]\"\n   ```\n\n2. Optionally add `django_typer` to your `INSTALLED_APPS` setting:\n\n   ```python\n   INSTALLED_APPS = [\n       ...\n       'django_typer',\n   ]\n   ```\n\n*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.*\n\n## Basic Example\n\n[TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) is a drop in extension to [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand). All of the documented features of [BaseCommand](https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand) work the same way!\n\n```python\nfrom django_typer.management import TyperCommand\n\nclass Command(TyperCommand):\n    def handle(self, arg1: str, arg2: str, arg3: float = 0.5, arg4: int = 1):\n        \"\"\"\n        A basic command that uses Typer\n        \"\"\"\n```\n\nOr, you may also use an interface identical to [Typer](https://typer.tiangolo.com/)'s. Simply import [Typer](https://typer.tiangolo.com/) from django_typer instead of typer.\n\n```python\nfrom django_typer.management import Typer\n\napp = Typer()\n\n@app.command()\ndef main(arg1: str, arg2: str, arg3: float = 0.5, arg4: int = 1):\n   \"\"\"\n   A basic command that uses Typer\n   \"\"\"\n```\n\n![Basic Example](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/basic.svg)\n\n## Multiple Subcommands Example\n\n\n\nCommands with multiple subcommands can be defined:\n\n```python\n   import typing as t\n\n   from django.utils.translation import gettext_lazy as _\n   from typer import Argument\n\n   from django_typer.management import TyperCommand, command\n\n\n   class Command(TyperCommand):\n      \"\"\"\n      A command that defines subcommands.\n      \"\"\"\n\n      @command()\n      def create(\n         self,\n         name: t.Annotated[str, Argument(help=_(\"The name of the object to create.\"))],\n      ):\n         \"\"\"\n         Create an object.\n         \"\"\"\n\n      @command()\n      def delete(\n         self, id: t.Annotated[int, Argument(help=_(\"The id of the object to delete.\"))]\n      ):\n         \"\"\"\n         Delete an object.\n         \"\"\"\n\n```\n\nOr using the typer-style interface this could be written:\n\n```python\nfrom django_typer.management import Typer\nimport typing as t\n\nfrom django.utils.translation import gettext_lazy as _\nfrom typer import Argument\n\napp = Typer(help=\"A command that defines subcommands.\")\n\n@app.command()\ndef create(\n   name: t.Annotated[str, Argument(help=_(\"The name of the object to create.\"))],\n):\n   \"\"\"\n   Create an object.\n   \"\"\"\n\n@app.command()\ndef delete(\n   id: t.Annotated[int, Argument(help=_(\"The id of the object to delete.\"))]\n):\n   \"\"\"\n   Delete an object.\n   \"\"\"\n```\n\n![Multiple Subcommands Example](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/multi.svg)\n![Multiple Subcommands Example - create](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/multi_create.svg)\n![Multiple Subcommands Example - delete](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/multi_delete.svg)\n\n\n## Grouping and Hierarchies Example\n\nMore 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:\n\n```bash\n./manage.py hierarchy math --precision 5 divide 10 2.1\n./manage.py hierarchy math multiply 10 2\n```\n\nUsing the class-based interface we could define the command like this:\n\n```python\n   import typing as t\n   from functools import reduce\n\n   from django.utils.translation import gettext_lazy as _\n   from typer import Argument, Option\n\n   from django_typer.management import TyperCommand, group\n\n\n   class Command(TyperCommand):\n\n      help = _(\"A more complex command that defines a hierarchy of subcommands.\")\n\n      precision = 2\n\n      @group(help=_(\"Do some math at the given precision.\"))\n      def math(\n         self,\n         precision: t.Annotated[\n            int, Option(help=_(\"The number of decimal places to output.\"))\n         ] = precision,\n      ):\n         self.precision = precision\n\n      # helps can be passed to the decorators\n      @math.command(help=_(\"Multiply the given numbers.\"))\n      def multiply(\n         self,\n         numbers: t.Annotated[\n            t.List[float], Argument(help=_(\"The numbers to multiply\"))\n         ],\n      ):\n         return f\"{reduce(lambda x, y: x * y, [1, *numbers]):.{self.precision}f}\"\n\n      # or if no help is supplied to the decorators, the docstring if present\n      # will be used!\n      @math.command()\n      def divide(\n         self,\n         numerator: t.Annotated[float, Argument(help=_(\"The numerator\"))],\n         denominator: t.Annotated[float, Argument(help=_(\"The denominator\"))],\n         floor: t.Annotated[bool, Option(help=_(\"Use floor division\"))] = False,\n      ):\n         \"\"\"\n         Divide the given numbers.\n         \"\"\"\n         if floor:\n               return str(numerator // denominator)\n         return f\"{numerator / denominator:.{self.precision}f}\"\n\n```\n\nThe typer-style interface builds a [TyperCommand](https://django-typer.readthedocs.io/en/latest/reference.html#django_typer.TyperCommand) class for us **that allows you to optionally accept the self argument in your commands.** We could define the above command using the typer interface like this:\n\n```python\n\nimport typing as t\nfrom functools import reduce\n\nfrom django.utils.translation import gettext_lazy as _\nfrom typer import Argument, Option\n\nfrom django_typer.management import Typer\n\n\napp = Typer(help=_(\"A more complex command that defines a hierarchy of subcommands.\"))\n\n\nmath_grp = Typer(help=_(\"Do some math at the given precision.\"))\n\napp.add_typer(math_grp)\n\n@math_grp.callback()\ndef math(\n   self,\n   precision: t.Annotated[\n      int, Option(help=_(\"The number of decimal places to output.\"))\n   ] = 2,\n):\n   self.precision = precision\n\n\n@math_grp.command(help=_(\"Multiply the given numbers.\"))\ndef multiply(\n   self,\n   numbers: t.Annotated[\n      t.List[float], Argument(help=_(\"The numbers to multiply\"))\n   ],\n):\n   return f\"{reduce(lambda x, y: x * y, [1, *numbers]):.{self.precision}f}\"\n\n@math_grp.command()\ndef divide(\n   self,\n   numerator: t.Annotated[float, Argument(help=_(\"The numerator\"))],\n   denominator: t.Annotated[float, Argument(help=_(\"The denominator\"))],\n   floor: t.Annotated[bool, Option(help=_(\"Use floor division\"))] = False,\n):\n   \"\"\"\n   Divide the given numbers.\n   \"\"\"\n   if floor:\n         return str(numerator // denominator)\n   return f\"{numerator / denominator:.{self.precision}f}\"\n```\n\n![Grouping and Hierarchies Example](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy.svg)\n![Grouping and Hierarchies Example - math](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy_math.svg)\n![Grouping and Hierarchies Example - math multiply](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy_math_multiply.svg)\n![Grouping and Hierarchies Example - math divide](https://raw.githubusercontent.com/django-commons/django-typer/main/examples/helps/hierarchy_math_divide.svg)\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Use Typer to define the CLI for your Django management commands.",
    "version": "2.3.0",
    "project_urls": {
        "Changelog": "https://django-typer.readthedocs.io/en/latest/changelog.html",
        "Code_of_Conduct": "https://github.com/django-commons/membership/blob/main/CODE_OF_CONDUCT.md",
        "Documentation": "https://django-typer.readthedocs.io",
        "Homepage": "https://django-typer.readthedocs.io",
        "Issues": "https://github.com/django-commons/django-typer/issues",
        "Repository": "https://github.com/django-commons/django-typer"
    },
    "split_keywords": [
        "django",
        " cli",
        " management",
        " typer",
        " commands"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e4e8866782b0bc1b4ea50b0e4a0d4d1e232350b4394cf6464656e5f022d7c4a2",
                "md5": "c1a5c263b9759de555dda8a6e2748ec2",
                "sha256": "e7e43019b120e579801bad82c0fca0b0b2c52069be661b0651442b016e558f66"
            },
            "downloads": -1,
            "filename": "django_typer-2.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c1a5c263b9759de555dda8a6e2748ec2",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.9",
            "size": 55973,
            "upload_time": "2024-10-13T06:02:18",
            "upload_time_iso_8601": "2024-10-13T06:02:18.720190Z",
            "url": "https://files.pythonhosted.org/packages/e4/e8/866782b0bc1b4ea50b0e4a0d4d1e232350b4394cf6464656e5f022d7c4a2/django_typer-2.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "91d3dd993ae74426920a38643696a34bdf9a21ab265588b124c0b595968839b0",
                "md5": "fc794ca4fdead51ddf870dff650d6832",
                "sha256": "3a2f5d8ce72b699df6a17cd83ad9f089903a216458c75d58ac6de18e8bca4dcd"
            },
            "downloads": -1,
            "filename": "django_typer-2.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "fc794ca4fdead51ddf870dff650d6832",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.9",
            "size": 54514,
            "upload_time": "2024-10-13T06:02:19",
            "upload_time_iso_8601": "2024-10-13T06:02:19.945124Z",
            "url": "https://files.pythonhosted.org/packages/91/d3/dd993ae74426920a38643696a34bdf9a21ab265588b124c0b595968839b0/django_typer-2.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-13 06:02:19",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "django-commons",
    "github_project": "membership",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "django-typer"
}
        
Elapsed time: 0.84866s