Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#2318): install CLI by default #2346

Merged
merged 25 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5278051
Install CLI by default
lsanpablo Sep 23, 2023
bf19348
docs: remove CLI extra from index
lsanpablo Sep 24, 2023
72d09ac
docs: minimal example can be done w/base install
lsanpablo Sep 24, 2023
1e6a40f
docs: move cli comment to the overview
lsanpablo Sep 24, 2023
79bc40e
feat: uvicorn is required as it was in the cli group
lsanpablo Sep 24, 2023
0ced34e
Merge branch 'main' into install_cli_by_default
JacobCoffee Sep 24, 2023
aaff5d7
feat: make uvicorn and jsbeautifier optional again
lsanpablo Sep 25, 2023
10b4a32
Merge branch 'main' into install_cli_by_default
JacobCoffee Sep 25, 2023
476c5f5
refactor: make sourcery suggested refactorings
lsanpablo Sep 25, 2023
30f265d
refactor: ignore possibly unbound variable uvicorn
lsanpablo Sep 25, 2023
8c28540
refactor: clarify pyright ignore reason
lsanpablo Sep 25, 2023
fccb463
refactor: don't use placeholder None for beautifier
lsanpablo Sep 25, 2023
b0e65fb
test: missing uvicorn and jsbeautifier are handled correctly
lsanpablo Sep 25, 2023
37c1f8d
ci: remove whitespace from empty lines
lsanpablo Sep 25, 2023
15ae11c
Merge branch 'main' into install_cli_by_default
lsanpablo Sep 25, 2023
e15a150
Update litestar/cli/commands/core.py
JacobCoffee Sep 26, 2023
e90cefd
Update docs/index.rst
lsanpablo Sep 26, 2023
047c327
Update docs/index.rst
lsanpablo Sep 26, 2023
26d6589
docs: remove extra whitespace
lsanpablo Sep 26, 2023
bd1d5dd
docs: clarify deprecation message
lsanpablo Sep 26, 2023
a60ef5e
docs: add missing space
lsanpablo Sep 26, 2023
e463f65
Merge branch 'main' into install_cli_by_default
lsanpablo Sep 27, 2023
7ae2fcb
docs: add removal in v3 message
lsanpablo Sep 27, 2023
ba64681
Merge branch 'main' into install_cli_by_default
lsanpablo Sep 27, 2023
d3a3d5c
chore: run `poetry lock --no-update`
lsanpablo Sep 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
JacobCoffee marked this conversation as resolved.
Show resolved Hide resolved
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