Skip to content

Commit adcb425

Browse files
committed
✨ Refactor: Introduce PostgresLifespanStateKeys enum for improved state management in lifespan setup
1 parent 9e56413 commit adcb425

File tree

2 files changed

+44
-20
lines changed

2 files changed

+44
-20
lines changed

packages/service-library/src/servicelib/fastapi/postgres_lifespan.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from collections.abc import AsyncIterator
3+
from enum import Enum # Added import
34

4-
from fastapi import FastAPI
55
from fastapi_lifespan_manager import LifespanManager, State
66
from servicelib.logging_utils import log_catch, log_context
77
from settings_library.postgres import PostgresSettings
@@ -15,17 +15,26 @@
1515
postgres_lifespan = LifespanManager()
1616

1717

18+
class PostgresLifespanStateKeys(str, Enum):
19+
POSTGRES_SETTINGS = "postgres_settings"
20+
POSTGRES_ASYNC_ENGINE = "postgres.async_engine"
21+
22+
1823
@postgres_lifespan.add
19-
async def setup_postgres_database(app: FastAPI) -> AsyncIterator[State]:
24+
async def setup_postgres_database(_, state: State) -> AsyncIterator[State]:
25+
2026
with log_context(_logger, logging.INFO, f"{__name__}"):
2127

22-
pg_settings: PostgresSettings = app.state.settings.CATALOG_POSTGRES
28+
pg_settings: PostgresSettings = state[
29+
PostgresLifespanStateKeys.POSTGRES_SETTINGS
30+
]
31+
assert isinstance(pg_settings, PostgresSettings) # nosec
2332

2433
async_engine: AsyncEngine = await create_async_engine_and_database_ready(
2534
pg_settings
2635
)
2736

28-
yield {"postgres.async_engine": async_engine}
37+
yield {PostgresLifespanStateKeys.POSTGRES_ASYNC_ENGINE: async_engine}
2938

3039
with log_catch(_logger, reraise=False):
3140
await async_engine.dispose()

packages/service-library/tests/fastapi/test_postgres_lifespan.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# pylint: disable=unused-argument
55
# pylint: disable=unused-variable
66

7+
from collections.abc import AsyncIterator
78
from typing import Annotated, Any
89

910
import pytest
@@ -14,7 +15,10 @@
1415
from pytest_mock import MockerFixture, MockType
1516
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
1617
from pytest_simcore.helpers.typing_env import EnvVarsDict
17-
from servicelib.fastapi.postgres_lifespan import postgres_lifespan
18+
from servicelib.fastapi.postgres_lifespan import (
19+
PostgresLifespanStateKeys,
20+
postgres_lifespan,
21+
)
1822
from settings_library.application import BaseApplicationSettings
1923
from settings_library.postgres import PostgresSettings
2024

@@ -41,33 +45,39 @@ async def test_setup_postgres_database_in_an_app(
4145
):
4246
assert app_environment
4347

44-
@postgres_lifespan.add
45-
async def my_db_setup(app: FastAPI, state: State):
46-
app.state.my_db_engine = state["postgres.async_engine"]
48+
class AppSettings(BaseApplicationSettings):
49+
CATALOG_POSTGRES: Annotated[
50+
PostgresSettings,
51+
Field(json_schema_extra={"auto_default_from_env": True}),
52+
]
53+
54+
async def my_app_settings(app: FastAPI) -> AsyncIterator[State]:
55+
app.state.settings = AppSettings.create_from_envs()
56+
57+
yield {
58+
PostgresLifespanStateKeys.POSTGRES_SETTINGS: app.state.settings.CATALOG_POSTGRES
59+
}
60+
61+
async def my_db_setup(app: FastAPI, state: State) -> AsyncIterator[State]:
62+
app.state.my_db_engine = state[PostgresLifespanStateKeys.POSTGRES_ASYNC_ENGINE]
4763

4864
assert (
4965
app.state.my_db_engine
5066
== mock_create_async_engine_and_database_ready.return_value
5167
)
5268

53-
yield
69+
yield {}
5470

5571
# compose lifespans
5672
app_lifespan = LifespanManager()
73+
app_lifespan.add(my_app_settings)
74+
75+
postgres_lifespan.add(my_db_setup)
5776
app_lifespan.include(postgres_lifespan)
5877

5978
# define app
6079
app = FastAPI(lifespan=app_lifespan)
6180

62-
# settings
63-
class AppSettings(BaseApplicationSettings):
64-
CATALOG_POSTGRES: Annotated[
65-
PostgresSettings,
66-
Field(json_schema_extra={"auto_default_from_env": True}),
67-
]
68-
69-
app.state.settings = AppSettings.create_from_envs()
70-
7181
async with ASGILifespanManager(
7282
app,
7383
startup_timeout=None if is_pdb_enabled else 10,
@@ -79,11 +89,16 @@ class AppSettings(BaseApplicationSettings):
7989
)
8090

8191
# Verify that the async engine is in the lifespan manager state
82-
assert "postgres.async_engine" in asgi_manager._state # noqa: SLF001
92+
assert (
93+
PostgresLifespanStateKeys.POSTGRES_ASYNC_ENGINE
94+
in asgi_manager._state # noqa: SLF001
95+
)
8396
assert app.state.my_db_engine
8497
assert (
8598
app.state.my_db_engine
86-
== asgi_manager._state["postgres.async_engine"] # noqa: SLF001
99+
== asgi_manager._state[ # noqa: SLF001
100+
PostgresLifespanStateKeys.POSTGRES_ASYNC_ENGINE
101+
]
87102
)
88103

89104
# Verify that the engine was disposed

0 commit comments

Comments
 (0)