From ccedcc3b88739bf07343c0d7d2c4137256b8c03f Mon Sep 17 00:00:00 2001 From: Artem Safronov Date: Wed, 11 Dec 2024 09:16:10 +0300 Subject: [PATCH 1/2] feat: add application state --- faststream/_internal/application.py | 32 ++++++++++++++++------- faststream/_internal/state/__init__.py | 3 +++ faststream/_internal/state/application.py | 28 ++++++++++++++++++++ tests/cli/test_app_state.py | 31 ++++++++++++++++++++++ 4 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 faststream/_internal/state/application.py create mode 100644 tests/cli/test_app_state.py diff --git a/faststream/_internal/application.py b/faststream/_internal/application.py index 85e0ba43d0..5f9c523797 100644 --- a/faststream/_internal/application.py +++ b/faststream/_internal/application.py @@ -16,7 +16,11 @@ from faststream._internal.constants import EMPTY from faststream._internal.context import ContextRepo from faststream._internal.log import logger -from faststream._internal.state import DIState +from faststream._internal.state import ( + BasicApplicationState, + DIState, + RunningApplicationState, +) from faststream._internal.state.broker import OuterBrokerState from faststream._internal.utils import apply_types from faststream._internal.utils.functions import ( @@ -99,13 +103,15 @@ def _init_setupable_( # noqa: PLW3201 serializer = PydanticSerializer() - self._state = DIState( - use_fastdepends=True, - get_dependent=None, - call_decorators=(), - serializer=serializer, - provider=self.provider, - context=self.context, + self._state = BasicApplicationState( + di_state=DIState( + use_fastdepends=True, + get_dependent=None, + call_decorators=(), + serializer=serializer, + provider=self.provider, + context=self.context, + ) ) self.broker = broker @@ -113,7 +119,7 @@ def _init_setupable_( # noqa: PLW3201 self._setup() def _setup(self) -> None: - self.broker._setup(OuterBrokerState(di_state=self._state)) + self.broker._setup(OuterBrokerState(di_state=self._state.di_state)) async def _start_broker(self) -> None: await self.broker.start() @@ -188,6 +194,8 @@ async def _startup( async with self._startup_logging(log_level=log_level): await self.start(**(run_extra_options or {})) + self._state = RunningApplicationState(di_state=self._state.di_state) + async def start( self, **run_extra_options: "SettingField", @@ -235,6 +243,8 @@ async def _shutdown(self, log_level: int = logging.INFO) -> None: async with self._shutdown_logging(log_level=log_level): await self.stop() + self._state = BasicApplicationState(di_state=self._state.di_state) + async def stop(self) -> None: """Executes shutdown hooks and stop broker.""" async with self._shutdown_hooks_context(): @@ -318,3 +328,7 @@ def after_shutdown( apply_types(to_async(func), context__=self.context) ) return func + + @property + def running(self) -> bool: + return self._state.running diff --git a/faststream/_internal/state/__init__.py b/faststream/_internal/state/__init__.py index f65fc1cb63..52641f2bff 100644 --- a/faststream/_internal/state/__init__.py +++ b/faststream/_internal/state/__init__.py @@ -1,3 +1,4 @@ +from .application import BasicApplicationState, RunningApplicationState from .broker import BrokerState, EmptyBrokerState from .fast_depends import DIState from .logger import LoggerParamsStorage, LoggerState @@ -6,6 +7,8 @@ __all__ = ( # state + "BasicApplicationState", + "RunningApplicationState", "BrokerState", # FastDepend "DIState", diff --git a/faststream/_internal/state/application.py b/faststream/_internal/state/application.py new file mode 100644 index 0000000000..e63aa3be29 --- /dev/null +++ b/faststream/_internal/state/application.py @@ -0,0 +1,28 @@ +from abc import ABC, abstractmethod + +from faststream._internal.state.fast_depends import DIState + + +class ApplicationState(ABC): + def __init__(self, di_state: DIState) -> None: + self._di_state = di_state + + @property + @abstractmethod + def running(self) -> bool: ... + + @property + def di_state(self) -> DIState: + return self._di_state + + +class BasicApplicationState(ApplicationState): + @property + def running(self) -> bool: + return False + + +class RunningApplicationState(ApplicationState): + @property + def running(self) -> bool: + return True diff --git a/tests/cli/test_app_state.py b/tests/cli/test_app_state.py new file mode 100644 index 0000000000..9896b8839a --- /dev/null +++ b/tests/cli/test_app_state.py @@ -0,0 +1,31 @@ +from unittest.mock import AsyncMock, patch + +import pytest + +from faststream import FastStream + + +@pytest.mark.asyncio() +async def test_state_running(app: FastStream) -> None: + with patch( + "faststream._internal.application.Application.start", new_callable=AsyncMock + ): + await app._startup() + + assert app.running + + +@pytest.mark.asyncio() +async def test_state_stopped(app: FastStream) -> None: + with ( + patch( + "faststream._internal.application.Application.start", new_callable=AsyncMock + ), + patch( + "faststream._internal.application.Application.stop", new_callable=AsyncMock + ), + ): + await app._startup() + await app._shutdown() + + assert not app.running From 34cf0970df52a44f1db99ac38c28b82e7f65c4a1 Mon Sep 17 00:00:00 2001 From: Artem-Safronov Date: Wed, 11 Dec 2024 21:31:57 +0000 Subject: [PATCH 2/2] docs: generate API References --- faststream/_internal/state/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/faststream/_internal/state/__init__.py b/faststream/_internal/state/__init__.py index 52641f2bff..47975c762b 100644 --- a/faststream/_internal/state/__init__.py +++ b/faststream/_internal/state/__init__.py @@ -8,7 +8,6 @@ __all__ = ( # state "BasicApplicationState", - "RunningApplicationState", "BrokerState", # FastDepend "DIState", @@ -17,6 +16,7 @@ # logging "LoggerState", "Pointer", + "RunningApplicationState", # proto "SetupAble", )