Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8bbe40d
FEAT: Adding --json output option in /cli/core.py on routes command
MauricioReisdoefer Oct 11, 2025
54257bf
FIX: Fixing --json routes cli command output
MauricioReisdoefer Oct 11, 2025
15f1024
fix: CI/CD failed tests corrected
MauricioReisdoefer Oct 11, 2025
cc900dd
fix: fixing validation and pre-commit format
MauricioReisdoefer Oct 11, 2025
e9ebdf3
fix: correcting pre-commit modification at AbstractSyncRepository
MauricioReisdoefer Oct 11, 2025
c251521
Merge branch 'main' into main
MauricioReisdoefer Oct 12, 2025
ac6179b
Merge branch 'main' into main
MauricioReisdoefer Oct 12, 2025
d12aa5d
fix: fixing _sync bar problem from validation
MauricioReisdoefer Oct 12, 2025
a24c622
test: test for non http routes in command --json
MauricioReisdoefer Oct 12, 2025
d00c8ec
test: remove coverage on non http routes of --json command
MauricioReisdoefer Oct 12, 2025
bc76a1b
Merge branch 'main' into main
MauricioReisdoefer Oct 15, 2025
6701d25
Merge branch 'main' into main
MauricioReisdoefer Oct 22, 2025
c54d492
feat: changing to --format=json
MauricioReisdoefer Oct 22, 2025
0a46b03
Merge branch 'main' of https://github.com/MauricioReisdoefer/litestar
MauricioReisdoefer Oct 22, 2025
9c6588d
Merge branch 'main' into main
MauricioReisdoefer Oct 22, 2025
f831916
test: fixing core tests
MauricioReisdoefer Oct 22, 2025
bd159ef
Merge branch 'main' of https://github.com/MauricioReisdoefer/litestar
MauricioReisdoefer Oct 22, 2025
68e0d49
fix: minor fixes
MauricioReisdoefer Oct 23, 2025
d53eceb
fix: fixing same problem
MauricioReisdoefer Oct 23, 2025
915e72d
test: creating new tests
MauricioReisdoefer Oct 23, 2025
c869c2d
Merge branch 'main' into main
MauricioReisdoefer Oct 27, 2025
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
38 changes: 35 additions & 3 deletions litestar/cli/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,9 @@ def run_command(

@click.command(name="routes")
@click.option("--schema", help="Include schema routes", is_flag=True, default=False)
@click.option("--exclude", help="routes to exclude via regex", type=str, is_flag=False, multiple=True)
def routes_command(app: Litestar, exclude: tuple[str, ...], schema: bool) -> None: # pragma: no cover
@click.option("--exclude", help="Routes to exclude via regex", type=str, is_flag=False, multiple=True)
@click.option("--format", "output_format", help="Output format (e.g., json, text)", default="text")
def routes_command(app: Litestar, exclude: tuple[str, ...], schema: bool, output_format: str) -> None:
"""Display information about the application's routes."""

sorted_routes = sorted(app.routes, key=lambda r: r.path)
Expand All @@ -319,7 +320,38 @@ def routes_command(app: Litestar, exclude: tuple[str, ...], schema: bool) -> Non
if exclude is not None:
sorted_routes = remove_routes_with_patterns(sorted_routes, exclude)

console.print(_RouteTree(sorted_routes))
if output_format == "json":
import inspect
import json

routes_list = []
for route in sorted_routes:
route_info: dict[str, Any] = {
"path": route.path,
"type": route.__class__.__name__,
"methods": sorted(getattr(route, "http_methods", [])),
}

if isinstance(route, HTTPRoute): # pragma: no cover
route_info["handlers"] = [
{
"name": h.name,
"path": h.paths,
"handler": h.handler_name,
"methods": sorted(h.http_methods),
"async": inspect.iscoroutinefunction(unwrap_partial(h.fn)),
}
for h in route.route_handlers
]

routes_list.append(route_info)

click.echo(json.dumps(routes_list, indent=4, default=lambda o: list(o) if isinstance(o, set) else o))

elif output_format == "text":
console.print(_RouteTree(sorted_routes))
else:
click.echo(f"Unsupported format: {output_format}")


class _RouteTree(Tree):
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/test_cli/test_core_commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import io
import json
import os
import re
import sys
Expand Down Expand Up @@ -668,3 +669,48 @@ def test_remove_routes_with_patterns() -> None:
assert len(paths) == 2
for route in ["/", "/foo"]:
assert route in paths


@pytest.mark.usefixtures("unset_env")
def test_routes_command_json_output(runner: CliRunner, create_app_file: CreateAppFileFixture) -> None:
"""Test that the routes command supports --format=json output."""
create_app_file("app.py", content=APP_FILE_CONTENT_ROUTES_EXAMPLE)

result = runner.invoke(cli_command, ["routes", "--format=json"])

assert result.exit_code == 0
assert result.exception is None

try:
data = json.loads(result.output)
except json.JSONDecodeError:
pytest.fail("Output is not valid JSON")

assert isinstance(data, list)
assert all("path" in route and "methods" in route for route in data)
assert len(data) > 0


@pytest.mark.usefixtures("unset_env")
def test_routes_command_text_output(runner: CliRunner, create_app_file: CreateAppFileFixture) -> None:
"""Test that the routes command supports --format=text output."""
create_app_file("app.py", content=APP_FILE_CONTENT_ROUTES_EXAMPLE)

result = runner.invoke(cli_command, ["routes", "--format=text"])

assert result.exit_code == 0
assert result.exception is None
assert "└──" in result.output or "/" in result.output
assert "path" not in result.output.lower()


@pytest.mark.usefixtures("unset_env")
def test_routes_command_unsupported_format(runner: CliRunner, create_app_file: CreateAppFileFixture) -> None:
"""Test that unsupported formats are handled gracefully."""
create_app_file("app.py", content=APP_FILE_CONTENT_ROUTES_EXAMPLE)

result = runner.invoke(cli_command, ["routes", "--format=yaml"])

assert result.exit_code == 0
assert "Unsupported format" in result.output
return
Loading