From 642f7fd5a8a5ae1cbbfc16b7ca3a274fd2a846ef Mon Sep 17 00:00:00 2001 From: Hafid Qarchi Date: Mon, 5 Aug 2024 22:10:27 +0900 Subject: [PATCH 1/6] fix test run error --- src/fastapi_cli/cli.py | 86 ++++++++++++++++++++++++++++++++++++++++++ tests/test_cli.py | 28 ++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/fastapi_cli/cli.py b/src/fastapi_cli/cli.py index d5bcb8e5..e8f7bea1 100644 --- a/src/fastapi_cli/cli.py +++ b/src/fastapi_cli/cli.py @@ -1,3 +1,5 @@ +import asyncio +from enum import Enum from logging import getLogger from pathlib import Path from typing import Any, Union @@ -16,6 +18,14 @@ app = typer.Typer(rich_markup_mode="rich") + +class WSProtocolType(str, Enum): + auto = "auto" + none = "none" + websockets = "websockets" + wsproto = "wsproto" + + setup_logging() logger = getLogger(__name__) @@ -60,6 +70,12 @@ def _run( command: str, app: Union[str, None] = None, proxy_headers: bool = False, + ws: type[asyncio.Protocol] | WSProtocolType = "auto", + ws_max_size: int = 16777216, + ws_max_queue: int = 32, + ws_ping_interval: float = 20.0, + ws_ping_timeout: float = 20.0, + ws_per_message_deflate: bool = True, ) -> None: try: use_uvicorn_app = get_import_string(path=path, app_name=app) @@ -97,6 +113,12 @@ def _run( workers=workers, root_path=root_path, proxy_headers=proxy_headers, + ws=ws, + ws_max_size=ws_max_size, + ws_max_queue=ws_max_queue, + ws_ping_interval=ws_ping_interval, + ws_ping_timeout=ws_ping_timeout, + ws_per_message_deflate=ws_per_message_deflate, ) @@ -145,6 +167,32 @@ def dev( help="Enable/Disable X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info." ), ] = True, + ws: Annotated[ + WSProtocolType, + typer.Option( + help="The WebSocket protocol.", case_sensitive=False, show_choices=True + ), + ] = WSProtocolType.auto, + ws_max_size: Annotated[ + int, + typer.Option(help="WebSocket max size message in bytes."), + ] = 16777216, + ws_max_queue: Annotated[ + int, + typer.Option(help="The maximum length of the WebSocket message queue."), + ] = 32, + ws_ping_interval: Annotated[ + float, + typer.Option(help="WebSocket ping interval in seconds."), + ] = 20.0, + ws_ping_timeout: Annotated[ + float, + typer.Option(help="WebSocket ping timeout in seconds."), + ] = 20.0, + ws_per_message_deflate: Annotated[ + bool, + typer.Option(help="WebSocket per-message-deflate compression"), + ] = True, ) -> Any: """ Run a [bold]FastAPI[/bold] app in [yellow]development[/yellow] mode. ๐Ÿงช @@ -180,6 +228,12 @@ def dev( app=app, command="dev", proxy_headers=proxy_headers, + ws=ws, + ws_max_size=ws_max_size, + ws_max_queue=ws_max_queue, + ws_ping_interval=ws_ping_interval, + ws_ping_timeout=ws_ping_timeout, + ws_per_message_deflate=ws_per_message_deflate, ) @@ -234,6 +288,32 @@ def run( help="Enable/Disable X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to populate remote address info." ), ] = True, + ws: Annotated[ + WSProtocolType, + typer.Option( + help="The WebSocket protocol.", case_sensitive=False, show_choices=True + ), + ] = WSProtocolType.auto, + ws_max_size: Annotated[ + int, + typer.Option(help="WebSocket max size message in bytes."), + ] = 16777216, + ws_max_queue: Annotated[ + int, + typer.Option(help="The maximum length of the WebSocket message queue."), + ] = 32, + ws_ping_interval: Annotated[ + float, + typer.Option(help="WebSocket ping interval in seconds."), + ] = 20.0, + ws_ping_timeout: Annotated[ + float, + typer.Option(help="WebSocket ping timeout in seconds."), + ] = 20.0, + ws_per_message_deflate: Annotated[ + bool, + typer.Option(help="WebSocket per-message-deflate compression"), + ] = True, ) -> Any: """ Run a [bold]FastAPI[/bold] app in [green]production[/green] mode. ๐Ÿš€ @@ -270,6 +350,12 @@ def run( app=app, command="run", proxy_headers=proxy_headers, + ws=ws, + ws_max_size=ws_max_size, + ws_max_queue=ws_max_queue, + ws_ping_interval=ws_ping_interval, + ws_ping_timeout=ws_ping_timeout, + ws_per_message_deflate=ws_per_message_deflate, ) diff --git a/tests/test_cli.py b/tests/test_cli.py index 44c14d2c..761c9d50 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -29,6 +29,12 @@ def test_dev() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, } assert "Using import string single_file_app:app" in result.output assert ( @@ -58,6 +64,8 @@ def test_dev_args() -> None: "--app", "api", "--no-proxy-headers", + "--ws", + "auto", ], ) assert result.exit_code == 0, result.output @@ -71,6 +79,12 @@ def test_dev_args() -> None: "workers": None, "root_path": "/api", "proxy_headers": False, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, } assert "Using import string single_file_app:api" in result.output assert ( @@ -97,6 +111,12 @@ def test_run() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, } assert "Using import string single_file_app:app" in result.output assert ( @@ -128,6 +148,8 @@ def test_run_args() -> None: "--app", "api", "--no-proxy-headers", + "--ws", + "websockets", ], ) assert result.exit_code == 0, result.output @@ -141,6 +163,12 @@ def test_run_args() -> None: "workers": 2, "root_path": "/api", "proxy_headers": False, + "ws": "websockets", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, } assert "Using import string single_file_app:api" in result.output assert ( From e9c8aea03bd0c583a18743afd178bd7765be163c Mon Sep 17 00:00:00 2001 From: Hafid Qarchi Date: Mon, 5 Aug 2024 22:29:25 +0900 Subject: [PATCH 2/6] fix var types --- src/fastapi_cli/cli.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/fastapi_cli/cli.py b/src/fastapi_cli/cli.py index e8f7bea1..4984c080 100644 --- a/src/fastapi_cli/cli.py +++ b/src/fastapi_cli/cli.py @@ -1,4 +1,3 @@ -import asyncio from enum import Enum from logging import getLogger from pathlib import Path @@ -70,7 +69,7 @@ def _run( command: str, app: Union[str, None] = None, proxy_headers: bool = False, - ws: type[asyncio.Protocol] | WSProtocolType = "auto", + ws: WSProtocolType = WSProtocolType.auto, ws_max_size: int = 16777216, ws_max_queue: int = 32, ws_ping_interval: float = 20.0, @@ -113,7 +112,7 @@ def _run( workers=workers, root_path=root_path, proxy_headers=proxy_headers, - ws=ws, + ws=ws.value, ws_max_size=ws_max_size, ws_max_queue=ws_max_queue, ws_ping_interval=ws_ping_interval, From 7c63cfacc00c6f0c7bff81c63e8543e016c9f811 Mon Sep 17 00:00:00 2001 From: Hafid Qarchi Date: Wed, 25 Feb 2026 16:46:33 +0000 Subject: [PATCH 3/6] =?UTF-8?q?=E2=9C=A8=20Add=20WebSocket=20options=20to?= =?UTF-8?q?=20the=20=5Frun=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fastapi_cli/cli.py | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/fastapi_cli/cli.py b/src/fastapi_cli/cli.py index 367fc6c5..96738550 100644 --- a/src/fastapi_cli/cli.py +++ b/src/fastapi_cli/cli.py @@ -248,27 +248,13 @@ def _run( proxy_headers=proxy_headers, forwarded_allow_ips=forwarded_allow_ips, log_config=get_uvicorn_log_config(), + ws=ws.value, + ws_max_size=ws_max_size, + ws_max_queue=ws_max_queue, + ws_ping_interval=ws_ping_interval, + ws_ping_timeout=ws_ping_timeout, + ws_per_message_deflate=ws_per_message_deflate, ) - print(Padding(panel, 1)) - if not uvicorn: - raise FastAPICLIException( - "Could not import Uvicorn, try running 'pip install uvicorn'" - ) from None - uvicorn.run( - app=use_uvicorn_app, - host=host, - port=port, - reload=reload, - workers=workers, - root_path=root_path, - proxy_headers=proxy_headers, - ws=ws.value, - ws_max_size=ws_max_size, - ws_max_queue=ws_max_queue, - ws_ping_interval=ws_ping_interval, - ws_ping_timeout=ws_ping_timeout, - ws_per_message_deflate=ws_per_message_deflate, - ) @app.command() From 1be0ba901e22c745b8b2fcb190d779ca0cc251b0 Mon Sep 17 00:00:00 2001 From: Hafid Qarchi Date: Wed, 25 Feb 2026 16:54:40 +0000 Subject: [PATCH 4/6] fix tests --- tests/test_cli.py | 52 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index dfe1dcf3..bb4f0bba 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,10 +4,10 @@ from unittest.mock import patch import uvicorn -from typer.testing import CliRunner - from fastapi_cli.cli import app from fastapi_cli.utils.cli import get_uvicorn_log_config +from typer.testing import CliRunner + from tests.utils import changing_dir runner = CliRunner() @@ -83,6 +83,12 @@ def test_dev_package() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "forwarded_allow_ips": None, "log_config": get_uvicorn_log_config(), } @@ -172,6 +178,12 @@ def test_dev_env_vars() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "forwarded_allow_ips": None, "log_config": get_uvicorn_log_config(), } @@ -210,6 +222,12 @@ def test_dev_env_vars_and_args() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "forwarded_allow_ips": None, "log_config": get_uvicorn_log_config(), } @@ -289,6 +307,12 @@ def test_run_trust_proxy() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "forwarded_allow_ips": "*", "log_config": get_uvicorn_log_config(), } @@ -376,6 +400,12 @@ def test_run_env_vars() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "forwarded_allow_ips": None, "log_config": get_uvicorn_log_config(), } @@ -410,6 +440,12 @@ def test_run_env_vars_and_args() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "forwarded_allow_ips": None, "log_config": get_uvicorn_log_config(), } @@ -523,6 +559,12 @@ def test_dev_with_import_string() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "log_config": get_uvicorn_log_config(), } assert "Using import string: single_file_app:api" in result.output @@ -545,6 +587,12 @@ def test_run_with_import_string() -> None: "workers": None, "root_path": "", "proxy_headers": True, + "ws": "auto", + "ws_max_size": 16777216, + "ws_max_queue": 32, + "ws_ping_interval": 20.0, + "ws_ping_timeout": 20.0, + "ws_per_message_deflate": True, "log_config": get_uvicorn_log_config(), } assert "Using import string: single_file_app:app" in result.output From c52b059af86cdbbe359d546135809ca4f474c48d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 16:55:52 +0000 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=8E=A8=20Auto=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index bb4f0bba..3b947991 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,10 +4,10 @@ from unittest.mock import patch import uvicorn -from fastapi_cli.cli import app -from fastapi_cli.utils.cli import get_uvicorn_log_config from typer.testing import CliRunner +from fastapi_cli.cli import app +from fastapi_cli.utils.cli import get_uvicorn_log_config from tests.utils import changing_dir runner = CliRunner() From cf7cd8f669cdd327f3ba16ee15d2b9afd39cd67e Mon Sep 17 00:00:00 2001 From: Hafid Qarchi Date: Wed, 25 Feb 2026 16:59:44 +0000 Subject: [PATCH 6/6] remove duplicate logger --- src/fastapi_cli/cli.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/fastapi_cli/cli.py b/src/fastapi_cli/cli.py index 96738550..dd173657 100644 --- a/src/fastapi_cli/cli.py +++ b/src/fastapi_cli/cli.py @@ -1,6 +1,5 @@ import logging from enum import Enum -from logging import getLogger from pathlib import Path from typing import Annotated, Any @@ -31,9 +30,6 @@ class WSProtocolType(str, Enum): wsproto = "wsproto" -setup_logging() -logger = getLogger(__name__) - try: import uvicorn except ImportError: # pragma: no cover