From bec39e098d21d655526af9f1ae1a3b5619ec5897 Mon Sep 17 00:00:00 2001 From: Ezeudoh Tochukwu Date: Fri, 24 Oct 2025 03:57:35 +0100 Subject: [PATCH 1/2] fixed session not closing --- ellar_sql/factory/base.py | 36 +++++++++++++++++++++++++++ ellar_sql/module.py | 23 ++++++++++------- requirements-tests.txt | 4 +-- samples/db-learning/tests/conftest.py | 2 +- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/ellar_sql/factory/base.py b/ellar_sql/factory/base.py index 6fff860..69f9fec 100644 --- a/ellar_sql/factory/base.py +++ b/ellar_sql/factory/base.py @@ -1,5 +1,7 @@ +import inspect import typing as t +import factory import sqlalchemy as sa import sqlalchemy.orm as sa_orm from ellar.threading import run_as_sync @@ -118,3 +120,37 @@ def _save( cls._session_execute(session.commit) cls._session_execute(session.refresh, obj) return obj + + +class EllarSQLSubFactoryId(factory.SubFactory): + """ + A SubFactory that returns the id of the created object. + """ + + def evaluate(self, instance, step, extra): + value = super().evaluate(instance, step, extra) + if inspect.isawaitable(value): + + async def resolve_value(): + resolved_value = await value + return resolved_value.id + + return resolve_value() + return value + + +class EllarSQLSubFactory(factory.SubFactory): + """ + A SubFactory that returns the created object. + """ + + def evaluate(self, instance, step, extra): + value = super().evaluate(instance, step, extra) + if inspect.isawaitable(value): + + async def resolve_value(): + resolved_value = await value + return resolved_value + + return resolve_value() + return value diff --git a/ellar_sql/module.py b/ellar_sql/module.py index f0167fd..837a5f3 100644 --- a/ellar_sql/module.py +++ b/ellar_sql/module.py @@ -27,6 +27,18 @@ def _raise_exception(): return _raise_exception +async def _session_cleanup( + db_service: EllarSQLService, session: t.Union[Session, AsyncSession] +) -> None: + res = db_service.session_factory.remove() + if isinstance(res, t.Coroutine): + await res + + res = session.close() + if isinstance(res, t.Coroutine): + await res + + @as_middleware async def session_middleware( context: IHostContext, call_next: t.Callable[..., t.Coroutine] @@ -40,15 +52,8 @@ async def session_middleware( try: await call_next() - except Exception as ex: - res = session.rollback() - if isinstance(res, t.Coroutine): - await res - raise ex - - res = db_service.session_factory.remove() - if isinstance(res, t.Coroutine): - await res + finally: + await _session_cleanup(db_service, session) @Module( diff --git a/requirements-tests.txt b/requirements-tests.txt index 2de4a39..03c97ca 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -4,9 +4,9 @@ autoflake ellar-cli >= 0.3.7 factory-boy >= 3.3.0 httpx -Pillow >=10.4.0, <11.2.0 mypy == 1.15.0 +Pillow >=10.4.0, <11.2.0 pytest >= 7.1.3,< 9.0.0 pytest-asyncio pytest-cov >= 2.12.0,< 7.0.0 -ruff ==0.9.9 +ruff ==0.13.3 diff --git a/samples/db-learning/tests/conftest.py b/samples/db-learning/tests/conftest.py index 6d49b3f..b16d33b 100644 --- a/samples/db-learning/tests/conftest.py +++ b/samples/db-learning/tests/conftest.py @@ -16,7 +16,7 @@ def tm(): test_module = Test.create_test_module(modules=[ApplicationModule]) app = test_module.create_application() - with execute_async_context_manager(app.application_context()): + with execute_async_context_manager(app.with_injector_context()): yield test_module From accb319ec2c5031243395c889c192b736e3729f8 Mon Sep 17 00:00:00 2001 From: Ezeudoh Tochukwu Date: Fri, 24 Oct 2025 03:58:56 +0100 Subject: [PATCH 2/2] 0.1.5 --- ellar_sql/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ellar_sql/__init__.py b/ellar_sql/__init__.py index d955062..43614ad 100644 --- a/ellar_sql/__init__.py +++ b/ellar_sql/__init__.py @@ -1,6 +1,6 @@ """EllarSQL Module adds support for SQLAlchemy and Alembic package to your Ellar application""" -__version__ = "0.1.3" +__version__ = "0.1.5" from .model.database_binds import get_all_metadata, get_metadata from .module import EllarSQLModule