lush-sqlalchemyx 0.4.0__tar.gz → 0.4.2__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.
Files changed (27) hide show
  1. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/PKG-INFO +2 -2
  2. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/pyproject.toml +2 -2
  3. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/__init__.py +7 -2
  4. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/base/dal/_common.py +14 -4
  5. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/integrations/fastapi/depends/__init__.py +15 -1
  6. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/integrations/flask/ext.py +3 -1
  7. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/README.md +0 -0
  8. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/_compat.py +0 -0
  9. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/base/__init__.py +0 -0
  10. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/base/dal/__init__.py +0 -0
  11. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/base/dal/_async.py +0 -0
  12. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/base/dal/_pagination.py +0 -0
  13. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/base/dal/_repository.py +0 -0
  14. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/base/dal/_sync.py +0 -0
  15. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/integrations/__init__.py +0 -0
  16. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/integrations/fastapi/__init__.py +0 -0
  17. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/integrations/flask/__init__.py +0 -0
  18. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/mgrs/__init__.py +0 -0
  19. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/mgrs/mysql/__init__.py +0 -0
  20. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/mgrs/mysql/manager.py +0 -0
  21. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/mgrs/mysql/mapper.py +0 -0
  22. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/mgrs/mysql/sync_manager.py +0 -0
  23. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/mgrs/mysql/sync_mapper.py +0 -0
  24. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/py.typed +0 -0
  25. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/same_impl_just_warn_wrapper.py +0 -0
  26. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/shortcuts/__init__.py +0 -0
  27. {lush_sqlalchemyx-0.4.0 → lush_sqlalchemyx-0.4.2}/src/lush_sqlalchemyx/shortcuts/meta.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: lush-sqlalchemyx
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: SQLAlchemy helpers (DAL) and async MySQL managers, with some web frameworks integrations
5
5
  Author: straydragon
6
6
  Author-email: straydragon <straydragonl@foxmail.com>
@@ -12,7 +12,7 @@ Requires-Dist: pydantic>=2.3.0,<3.0.0
12
12
  Requires-Dist: typing-extensions>=4.12.2
13
13
  Requires-Dist: lush-pydanticx>=0.1.0
14
14
  Requires-Dist: lush-stdx>=0.1.0
15
- Requires-Dist: lush-dal-protocol>=0.1.0
15
+ Requires-Dist: lush-dal-protocol>=0.2.2
16
16
  Requires-Dist: sqlalchemy[asyncio]>=2.0.43 ; extra == 'asyncio'
17
17
  Requires-Dist: flask-sqlalchemy>=3.1.1 ; extra == 'flask'
18
18
  Requires-Python: >=3.10
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lush-sqlalchemyx"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  description = "SQLAlchemy helpers (DAL) and async MySQL managers, with some web frameworks integrations"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -16,7 +16,7 @@ dependencies = [
16
16
  "typing-extensions>=4.12.2",
17
17
  "lush-pydanticx>=0.1.0",
18
18
  "lush-stdx>=0.1.0",
19
- "lush-dal-protocol>=0.1.0",
19
+ "lush-dal-protocol>=0.2.2",
20
20
  ]
21
21
 
22
22
  [project.optional-dependencies]
@@ -1,7 +1,12 @@
1
1
  """lush-sqlalchemyx — SQLAlchemy DAL 实现 + async/sync MySQL manager + 框架集成.
2
2
 
3
- 导入本包时会自动注册软删除 Session 事件监听器.
4
- 如需显式管理钩子生命周期, 参见 :func:`register_soft_delete_hooks` 等.
3
+ 使用前须在应用启动时调用 :func:`setup_dal_hooks` 注册 Session 事件监听器:
4
+
5
+ - Flask: 使用 ``LushFlaskSQLAlchemy.init_db()`` 时自动调用
6
+ - FastAPI: 在 ``lifespan`` 中调用 ``setup_dal_hooks()``
7
+ - 其他场景: 在创建 Session 前调用一次 ``setup_dal_hooks()``
8
+
9
+ 不调用则软删除、只读保护等钩子不会生效。
5
10
  """
6
11
 
7
12
  from lush_sqlalchemyx.base.dal import (
@@ -343,6 +343,11 @@ def setup_dal_hooks() -> None:
343
343
  在应用生命周期开始时**调用一次**即可,无需关注具体注册了哪些钩子。
344
344
  涵盖:软删除拦截、软删除查询过滤、只读保护。
345
345
 
346
+ **时序说明**: 模型类的定义(继承 SoftDeleteTableMixin / ReadOnlyMixin)
347
+ 可以在调用 setup_dal_hooks 之前或之后 — 均不影响钩子生效。
348
+ 因为钩子注册在 SyncSession 上,在 flush/query 时通过 isinstance 和
349
+ with_loader_criteria 动态评估,不依赖模型类在注册时刻的状态。
350
+
346
351
  FastAPI 示例::
347
352
 
348
353
  @asynccontextmanager
@@ -364,11 +369,18 @@ def setup_dal_hooks() -> None:
364
369
 
365
370
  # ---------------------------------------------------------------------------
366
371
  # Session event listeners (registered on SyncSession — works for both sync
367
- # and async since AsyncSession delegates to a SyncSession internally)
372
+ # and async since AsyncSession delegates to a SyncSession internally).
373
+ #
374
+ # 不再使用 @sa_event.listens_for 装饰器在 import 时自动注册。
375
+ # 改为通过 setup_dal_hooks() / register_soft_delete_hooks() 显式注册。
376
+ # 这样做的原因: 让注册时机清晰可预测, 避免用户对"何时调用 setup_dal_hooks"
377
+ # 产生困惑。在 Flask/FastAPI 集成中 auto-call 保证开箱即用。
378
+ #
379
+ # 模型类定义在 setup_dal_hooks 之前或之后均不影响钩子生效 —
380
+ # isinstance 和 with_loader_criteria 在 flush/query 时动态评估。
368
381
  # ---------------------------------------------------------------------------
369
382
 
370
383
 
371
- @sa_event.listens_for(SyncSession, "before_flush")
372
384
  def __receive_before_flush(session: SyncSession, flush_context: Any, instances: Any) -> None: # noqa: ARG001 # pyright: ignore[reportUnusedFunction, reportUnusedParameter]
373
385
  for instance in session.deleted:
374
386
  if isinstance(instance, SoftDeleteTableMixin):
@@ -376,7 +388,6 @@ def __receive_before_flush(session: SyncSession, flush_context: Any, instances:
376
388
  session.add(instance)
377
389
 
378
390
 
379
- @sa_event.listens_for(SyncSession, "do_orm_execute")
380
391
  def __add_filtering_criteria(execute_state: ORMExecuteState) -> None: # pyright: ignore[reportUnusedFunction]
381
392
  if (
382
393
  not execute_state.is_column_load
@@ -393,7 +404,6 @@ def __add_filtering_criteria(execute_state: ORMExecuteState) -> None: # pyright
393
404
  )
394
405
 
395
406
 
396
- @sa_event.listens_for(SyncSession, "before_flush")
397
407
  def __prevent_readonly_write(session: SyncSession, flush_context: Any, instances: Any) -> None: # noqa: ARG001 # pyright: ignore[reportUnusedFunction, reportUnusedParameter]
398
408
  for obj in session.new.union(session.dirty).union(session.deleted):
399
409
  if isinstance(obj, ReadOnlyMixin):
@@ -1,4 +1,18 @@
1
- """FastAPI 依赖工厂:为 AsyncMySQL 管理器与会话提供依赖注入工具."""
1
+ """FastAPI 依赖工厂:为 AsyncMySQL 管理器与会话提供依赖注入工具.
2
+
3
+ 使用本模块前, 请在 FastAPI lifespan 中调用 ``setup_dal_hooks()``::
4
+
5
+ from contextlib import asynccontextmanager
6
+ from lush_sqlalchemyx import setup_dal_hooks
7
+
8
+
9
+ @asynccontextmanager
10
+ async def lifespan(app):
11
+ setup_dal_hooks()
12
+ yield
13
+
14
+ 不调用则软删除、只读保护等 Session 事件钩子不会生效.
15
+ """
2
16
 
3
17
  from collections.abc import AsyncIterator, Awaitable, Callable
4
18
  from typing import ClassVar, Generic
@@ -29,6 +29,7 @@ except ImportError as _exc: # pragma: no cover
29
29
 
30
30
  from sqlalchemy.orm import Session
31
31
 
32
+ from lush_sqlalchemyx import setup_dal_hooks
32
33
  from lush_sqlalchemyx.base.dal._common import CUModelT, DTOModelT, SQLATableT
33
34
  from lush_sqlalchemyx.base.dal._sync import SyncBaseDAL, SyncReadDAL, SyncWriteDAL
34
35
  from lush_sqlalchemyx.mgrs.mysql.sync_manager import SyncMySQLManager
@@ -66,9 +67,10 @@ class LushFlaskSQLAlchemy:
66
67
  self.init_db(db)
67
68
 
68
69
  def init_db(self, db: SQLAlchemy) -> None:
69
- """绑定到 Flask-SQLAlchemy 实例."""
70
+ """绑定到 Flask-SQLAlchemy 实例, 并注册 DAL Session 事件钩子."""
70
71
  self._db = db
71
72
  self._manager = SyncMySQLManager.from_engine(db.engine)
73
+ setup_dal_hooks()
72
74
 
73
75
  @property
74
76
  def manager(self) -> SyncMySQLManager: