Skip to content

Commit

Permalink
feat(#2318): install CLI by default (#2346)
Browse files Browse the repository at this point in the history
Co-authored-by: Jacob Coffee <jacob@z7x.org>
  • Loading branch information
lsanpablo and JacobCoffee committed Sep 27, 2023
1 parent 4aac36d commit ab84566
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 76 deletions.
17 changes: 10 additions & 7 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Litestar is a powerful, flexible, highly performant, and opinionated ASGI framew
The Litestar framework supports :doc:`/usage/plugins`, ships
with :doc:`dependency injection </usage/dependency-injection>`, :doc:`security primitives </usage/security/index>`,
:doc:`OpenAPI schema generation </usage/openapi>`, `MessagePack <https://msgpack.org/>`_,
:doc:`middlewares </usage/middleware/index>`, and much more.
:doc:`middlewares </usage/middleware/index>`, a great :doc:`CLI </usage/cli>` experience, and much more.

Installation
------------
Expand All @@ -15,10 +15,7 @@ Installation
pip install litestar
.. tip:: ``litestar[standard]`` includes everything you need to get started with Litestar. It has: ``click`` and ``rich`` for a great CLI experience, ``jinja2`` for templating,
and ``uvicorn`` for running your app.

You can also install just the :doc:`CLI </usage/cli>` with ``litestar[cli]``!
.. tip:: ``litestar[standard]`` includes commonly used extras like ``uvicorn`` and ``jinja2`` (for templating).

.. dropdown:: Extras
:icon: star
Expand Down Expand Up @@ -57,6 +54,12 @@ Installation
:code:`pip install litestar[sqlalchemy]`

:doc:`CLI </usage/cli>`
.. deprecated:: 2.1.1
The ``litestar`` base installation now includes the CLI dependencies and this group is no longer required
to use the CLI.
If you need the optional CLI dependencies, install the ``standard`` group instead.
**Will be removed in 3.0**

:code:`pip install litestar[cli]`

:doc:`Jinja Templating </usage/templating>`
Expand All @@ -65,7 +68,7 @@ Installation
:doc:`Mako Templating </usage/templating>`
:code:`pip install litestar[mako]`

Standard Installation (includes CLI and Jinja templating):
Standard Installation (includes Uvicorn and Jinja2 templating):
:code:`pip install litestar[standard]`

All Extras:
Expand All @@ -77,7 +80,7 @@ Installation
Minimal Example
---------------

At a minimum, make sure you have installed ``litestar[standard]``, which includes ``litestar``, the CLI, and uvicorn.
At a minimum, make sure you have installed ``litestar[standard]``, which includes uvicorn.

First, create a file named ``app.py`` with the following contents:

Expand Down
24 changes: 9 additions & 15 deletions docs/usage/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,22 @@ CLI
===

Litestar provides a convenient command line interface (CLI) for running and managing Litestar applications. The CLI is
powered by `click <https://click.palletsprojects.com/>`_ and `rich <https://rich.readthedocs.io>`_.
powered by `click <https://click.palletsprojects.com/>`_, `rich <https://rich.readthedocs.io>`_,
and `rich-click <https://github.com/ewels/rich-click>`_.

Enabling the CLI
----------------
Enabling all CLI features
-------------------------

By default, the CLI dependencies are not included during the installation of Litestar to minimize the required packages.
To enable the CLI, you need to install Litestar with the ``cli`` or ``standard`` extras:

.. code-block:: shell
pip install litestar[cli]
The CLI and its hard dependencies are included by default. However, if you want to run your application
(using ``litestar run`` ) or beautify the Typescript generated by the ``litestar schema typescript``
command, you'll need ``uvicorn`` and ``jsbeautifier`` . They can be installed independently, but we
recommend installing the ``standard`` group which conveniently bundles commonly used optional dependencies.

.. code-block:: shell
pip install litestar[standard]
Once you have installed either of these, you can access the CLI functionality through the ``litestar`` command.

.. note::
Installing the CLI automatically includes the ``click``, ``rich``, and ``rich-click`` packages. While we recommend
using ``rich-click`` for the best experience, it is an optional dependency. If you prefer not to use it, you can
manually install ``click`` and ``rich`` in your project instead of using the built-in Litestar extras flag.
Once you have installed ``standard``, you'll have access to the ``litestar run`` command.

Autodiscovery
-------------
Expand Down
15 changes: 12 additions & 3 deletions litestar/cli/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,20 @@
from litestar.utils import get_name

RICH_CLICK_INSTALLED = False
try:
with contextlib.suppress(ImportError):
import rich_click # noqa: F401

RICH_CLICK_INSTALLED = True
except ImportError:
pass
UVICORN_INSTALLED = False
with contextlib.suppress(ImportError):
import uvicorn # noqa: F401

UVICORN_INSTALLED = True
JSBEAUTIFIER_INSTALLED = False
with contextlib.suppress(ImportError):
import jsbeautifier # noqa: F401

JSBEAUTIFIER_INSTALLED = True
if TYPE_CHECKING or not RICH_CLICK_INSTALLED: # pragma: no cover
from click import ClickException, Command, Context, Group, pass_context
else:
Expand All @@ -37,6 +44,8 @@

__all__ = (
"RICH_CLICK_INSTALLED",
"UVICORN_INSTALLED",
"JSBEAUTIFIER_INSTALLED",
"LoadedApp",
"LitestarCLIException",
"LitestarEnv",
Expand Down
19 changes: 15 additions & 4 deletions litestar/cli/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import sys
from typing import TYPE_CHECKING, Any

import uvicorn
from rich.tree import Tree

from litestar.cli._utils import RICH_CLICK_INSTALLED, LitestarEnv, console, show_app_info
from litestar.cli._utils import RICH_CLICK_INSTALLED, UVICORN_INSTALLED, LitestarEnv, console, show_app_info
from litestar.routes import HTTPRoute, WebSocketRoute
from litestar.utils.helpers import unwrap_partial

if UVICORN_INSTALLED:
import uvicorn

if TYPE_CHECKING or not RICH_CLICK_INSTALLED: # pragma: no cover
import click
from click import Context, command, option
Expand Down Expand Up @@ -95,7 +97,7 @@ def run_command(
pdb: bool,
ctx: Context,
) -> None:
"""Run a Litestar app.
"""Run a Litestar app; requires ``uvicorn``.
The app can be either passed as a module path in the form of <module name>.<submodule>:<app instance or factory>,
set as an environment variable LITESTAR_APP with the same format or automatically discovered from one of these
Expand All @@ -110,6 +112,12 @@ def run_command(
if pdb:
os.environ["LITESTAR_PDB"] = "1"

if not UVICORN_INSTALLED:
console.print(
r"uvicorn is not installed. Please install the standard group, litestar\[standard], to use this command."
)
sys.exit(1)

if callable(ctx.obj):
ctx.obj = ctx.obj()
else:
Expand All @@ -135,7 +143,10 @@ def run_command(
show_app_info(app)

if workers == 1 and not reload:
uvicorn.run(
# A guard statement at the beginning of this function prevents uvicorn from being unbound
# See "reportUnboundVariable in:
# https://microsoft.github.io/pyright/#/configuration?id=type-check-diagnostics-settings
uvicorn.run( # pyright: ignore
app=env.app_path,
host=host,
port=port,
Expand Down
16 changes: 10 additions & 6 deletions litestar/cli/commands/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
from pathlib import Path
from typing import TYPE_CHECKING

from jsbeautifier import Beautifier
from yaml import dump as dump_yaml

from litestar import Litestar
from litestar._openapi.typescript_converter.converter import (
convert_openapi_to_typescript,
)
from litestar.cli._utils import RICH_CLICK_INSTALLED, LitestarCLIException, LitestarGroup
from litestar.cli._utils import JSBEAUTIFIER_INSTALLED, RICH_CLICK_INSTALLED, LitestarCLIException, LitestarGroup

if TYPE_CHECKING or not RICH_CLICK_INSTALLED: # pragma: no cover
from click import Path as ClickPath
Expand All @@ -18,11 +17,13 @@
from rich_click import Path as ClickPath
from rich_click import group, option

if JSBEAUTIFIER_INSTALLED: # pragma: no cover
from jsbeautifier import Beautifier

__all__ = ("generate_openapi_schema", "generate_typescript_specs", "schema_group")
beautifier = Beautifier()


beautifier = Beautifier()
__all__ = ("generate_openapi_schema", "generate_typescript_specs", "schema_group")


@group(cls=LitestarGroup, name="schema")
Expand Down Expand Up @@ -64,7 +65,10 @@ def generate_typescript_specs(app: Litestar, output: Path, namespace: str) -> No
"""Generate TypeScript specs from the OpenAPI schema."""
try:
specs = convert_openapi_to_typescript(app.openapi_schema, namespace)
beautified_output = beautifier.beautify(specs.write())
output.write_text(beautified_output)
# beautifier will be defined if JSBEAUTIFIER_INSTALLED is True
specs_output = (
beautifier.beautify(specs.write()) if JSBEAUTIFIER_INSTALLED else specs.write() # pyright: ignore
)
output.write_text(specs_output)
except OSError as e: # pragma: no cover
raise LitestarCLIException(f"failed to write schema to path {output}") from e
Loading

0 comments on commit ab84566

Please sign in to comment.