hexcore 1.6.2__tar.gz → 1.6.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hexcore-1.6.2 → hexcore-1.6.3}/PKG-INFO +1 -1
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/session.py +2 -7
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/uow/__init__.py +8 -4
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore.egg-info/PKG-INFO +1 -1
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore.egg-info/SOURCES.txt +2 -1
- {hexcore-1.6.2 → hexcore-1.6.3}/pyproject.toml +1 -1
- hexcore-1.6.3/tests/test_uow_session_regression.py +110 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/LICENSE +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/README.md +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/__main__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/dtos/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/dtos/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/dtos/base.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/dtos/base.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/use_cases/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/use_cases/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/use_cases/base.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/application/use_cases/base.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/config.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/config.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/auth/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/auth/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/auth/permissions.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/auth/permissions.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/auth/value_objects.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/auth/value_objects.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/base.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/base.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/events.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/events.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/exceptions.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/exceptions.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/repositories.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/repositories.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/services.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/services.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/uow.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/domain/uow.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/api/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/api/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/api/utils.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/api/utils.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/cache_backends/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/cache_backends/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/cache_backends/memory.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/cache_backends/memory.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/cache_backends/redis.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cache/cache_backends/redis.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cli.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/cli.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/events/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/events/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/events/events_backends/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/events/events_backends/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/events/events_backends/memory.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/events/events_backends/memory.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/base.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/base.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/decorators.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/decorators.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/implementations.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/implementations.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/beanie/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/beanie/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/beanie/utils.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/beanie/utils.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/session.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/utils.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/utils.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/utils.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/utils.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/uow/__init__.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/uow/decorators.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/uow/decorators.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/uow/helpers.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/uow/helpers.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/types.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore/types.pyi +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore.egg-info/dependency_links.txt +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore.egg-info/entry_points.txt +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore.egg-info/requires.txt +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/hexcore.egg-info/top_level.txt +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/scripts/__init__.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/scripts/fix_pyi_files.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/scripts/fix_types_pyi_aliases.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/scripts/main.py +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/setup.cfg +0 -0
- {hexcore-1.6.2 → hexcore-1.6.3}/tests/test_basic.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexcore
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.3
|
|
4
4
|
Summary: Núcleo reutilizable para proyectos Python con arquitectura hexagonal y event handling. Provee abstracciones, utilidades y contratos para DDD, eventos y desacoplamiento de infraestructura.
|
|
5
5
|
Author-email: "David Latosefki (Indroic)" <indroic@outlook.com>
|
|
6
6
|
License-Expression: MIT
|
{hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/session.py
RENAMED
|
@@ -23,11 +23,6 @@ AsyncSessionLocal: async_sessionmaker[AsyncSession] = async_sessionmaker(
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
async def get_async_db_session():
|
|
26
|
-
"""Generador de sesiones asíncronas
|
|
26
|
+
"""Generador de sesiones asíncronas delegando el ciclo de vida al context manager."""
|
|
27
27
|
async with AsyncSessionLocal() as db:
|
|
28
|
-
|
|
29
|
-
yield db
|
|
30
|
-
except Exception:
|
|
31
|
-
if db.in_transaction():
|
|
32
|
-
await db.rollback()
|
|
33
|
-
raise
|
|
28
|
+
yield db
|
|
@@ -39,16 +39,20 @@ class SqlAlchemyUnitOfWork(IUnitOfWork):
|
|
|
39
39
|
exc_tb: t.Optional[t.Any],
|
|
40
40
|
) -> None:
|
|
41
41
|
# El ciclo de vida de la sesion se maneja en la dependencia/factory
|
|
42
|
-
# que la crea.
|
|
43
|
-
|
|
42
|
+
# que la crea. Evitamos rollback duplicado para no interferir con
|
|
43
|
+
# el unwind del contexto externo de AsyncSession.
|
|
44
|
+
if exc_type:
|
|
45
|
+
self.clear_tracked_entities()
|
|
44
46
|
|
|
45
47
|
async def commit(self):
|
|
46
48
|
"""
|
|
47
49
|
Confirma la transacción y despacha los eventos.
|
|
48
50
|
"""
|
|
49
51
|
await self.session.commit()
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
try:
|
|
53
|
+
await self.dispatch_events()
|
|
54
|
+
finally:
|
|
55
|
+
self.clear_tracked_entities()
|
|
52
56
|
|
|
53
57
|
async def rollback(self):
|
|
54
58
|
if self.session.in_transaction():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexcore
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.3
|
|
4
4
|
Summary: Núcleo reutilizable para proyectos Python con arquitectura hexagonal y event handling. Provee abstracciones, utilidades y contratos para DDD, eventos y desacoplamiento de infraestructura.
|
|
5
5
|
Author-email: "David Latosefki (Indroic)" <indroic@outlook.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from collections.abc import AsyncGenerator
|
|
3
|
+
from types import TracebackType
|
|
4
|
+
from typing import Any, cast
|
|
5
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
6
|
+
|
|
7
|
+
from hexcore.infrastructure.repositories.orms.sqlalchemy.session import (
|
|
8
|
+
get_async_db_session,
|
|
9
|
+
)
|
|
10
|
+
from hexcore.infrastructure.uow import SqlAlchemyUnitOfWork
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class _DummySessionContext:
|
|
14
|
+
def __init__(self, session: Any) -> None:
|
|
15
|
+
self._session = session
|
|
16
|
+
|
|
17
|
+
async def __aenter__(self) -> Any:
|
|
18
|
+
return self._session
|
|
19
|
+
|
|
20
|
+
async def __aexit__(
|
|
21
|
+
self,
|
|
22
|
+
exc_type: type[BaseException] | None,
|
|
23
|
+
exc_val: BaseException | None,
|
|
24
|
+
exc_tb: TracebackType | None,
|
|
25
|
+
) -> bool:
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _build_sql_uow(session: Any) -> SqlAlchemyUnitOfWork:
|
|
30
|
+
with patch("hexcore.infrastructure.uow.discover_sql_repositories", return_value={}):
|
|
31
|
+
return SqlAlchemyUnitOfWork(session=session)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_async_db_session_no_manual_rollback_on_error():
|
|
35
|
+
async def _run():
|
|
36
|
+
session = MagicMock()
|
|
37
|
+
session.rollback = AsyncMock()
|
|
38
|
+
|
|
39
|
+
with patch(
|
|
40
|
+
"hexcore.infrastructure.repositories.orms.sqlalchemy.session.AsyncSessionLocal",
|
|
41
|
+
return_value=_DummySessionContext(session),
|
|
42
|
+
):
|
|
43
|
+
session_generator = cast(AsyncGenerator[Any, None], get_async_db_session())
|
|
44
|
+
yielded = await anext(session_generator)
|
|
45
|
+
assert yielded is session
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
await session_generator.athrow(ValueError("boom"))
|
|
49
|
+
except ValueError:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
session.rollback.assert_not_awaited()
|
|
53
|
+
|
|
54
|
+
asyncio.run(_run())
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_sql_uow_aexit_does_not_rollback_session():
|
|
58
|
+
async def _run():
|
|
59
|
+
session = MagicMock()
|
|
60
|
+
session.rollback = AsyncMock()
|
|
61
|
+
|
|
62
|
+
uow = _build_sql_uow(session)
|
|
63
|
+
uow.clear_tracked_entities = MagicMock()
|
|
64
|
+
|
|
65
|
+
await uow.__aexit__(ValueError, ValueError("boom"), None)
|
|
66
|
+
|
|
67
|
+
session.rollback.assert_not_awaited()
|
|
68
|
+
uow.clear_tracked_entities.assert_called_once()
|
|
69
|
+
|
|
70
|
+
asyncio.run(_run())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_sql_uow_rollback_keeps_explicit_rollback_behavior():
|
|
74
|
+
async def _run():
|
|
75
|
+
session = MagicMock()
|
|
76
|
+
session.in_transaction.return_value = True
|
|
77
|
+
session.rollback = AsyncMock()
|
|
78
|
+
|
|
79
|
+
uow = _build_sql_uow(session)
|
|
80
|
+
uow.clear_tracked_entities = MagicMock()
|
|
81
|
+
|
|
82
|
+
await uow.rollback()
|
|
83
|
+
|
|
84
|
+
session.rollback.assert_awaited_once()
|
|
85
|
+
uow.clear_tracked_entities.assert_called_once()
|
|
86
|
+
|
|
87
|
+
asyncio.run(_run())
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_sql_uow_commit_clears_entities_even_if_dispatch_fails():
|
|
91
|
+
async def _run():
|
|
92
|
+
session = MagicMock()
|
|
93
|
+
session.commit = AsyncMock()
|
|
94
|
+
|
|
95
|
+
uow = _build_sql_uow(session)
|
|
96
|
+
uow.dispatch_events = AsyncMock(side_effect=RuntimeError("dispatch failed"))
|
|
97
|
+
uow.clear_tracked_entities = MagicMock()
|
|
98
|
+
|
|
99
|
+
raised = None
|
|
100
|
+
try:
|
|
101
|
+
await uow.commit()
|
|
102
|
+
except RuntimeError as exc:
|
|
103
|
+
raised = exc
|
|
104
|
+
|
|
105
|
+
assert raised is not None
|
|
106
|
+
session.commit.assert_awaited_once()
|
|
107
|
+
uow.dispatch_events.assert_awaited_once()
|
|
108
|
+
uow.clear_tracked_entities.assert_called_once()
|
|
109
|
+
|
|
110
|
+
asyncio.run(_run())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/beanie/__init__.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/__init__.py
RENAMED
|
File without changes
|
{hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/__init__.pyi
RENAMED
|
File without changes
|
{hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/session.pyi
RENAMED
|
File without changes
|
{hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/utils.py
RENAMED
|
File without changes
|
{hexcore-1.6.2 → hexcore-1.6.3}/hexcore/infrastructure/repositories/orms/sqlalchemy/utils.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|