sdpy-kit 0.1.0__py3-none-any.whl
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.
- kit/__init__.py +68 -0
- kit/ai/__init__.py +47 -0
- kit/ai/base_service.py +94 -0
- kit/ai/chat_service.py +110 -0
- kit/ai/embedding_service.py +133 -0
- kit/ai/exceptions.py +57 -0
- kit/ai/failover.py +244 -0
- kit/ai/image_service.py +99 -0
- kit/ai/model_builder.py +119 -0
- kit/ai/model_client.py +214 -0
- kit/ai/pool.py +411 -0
- kit/ai/profiles.py +373 -0
- kit/ai/rerank_service.py +93 -0
- kit/ai/runner.py +580 -0
- kit/ai/types.py +28 -0
- kit/common_kit.py +221 -0
- kit/config/__init__.py +44 -0
- kit/config/kit_config.py +147 -0
- kit/config/log_config.py +134 -0
- kit/db/__init__.py +70 -0
- kit/db/base_db_kit.py +406 -0
- kit/db/crud.py +361 -0
- kit/db/engine.py +230 -0
- kit/db/exceptions.py +34 -0
- kit/db/models/__init__.py +33 -0
- kit/db/models/base.py +56 -0
- kit/db/mysql_kit.py +89 -0
- kit/db/pg_kit.py +87 -0
- kit/db/session.py +85 -0
- kit/db/sqlite_kit.py +284 -0
- kit/db/transaction.py +109 -0
- kit/doc_kit.py +1502 -0
- kit/file_kit.py +429 -0
- kit/mcp_kit.py +547 -0
- kit/mineru_kit.py +918 -0
- kit/redis_kit.py +392 -0
- kit/zvec_kit.py +671 -0
- sdpy_kit-0.1.0.dist-info/METADATA +128 -0
- sdpy_kit-0.1.0.dist-info/RECORD +40 -0
- sdpy_kit-0.1.0.dist-info/WHEEL +4 -0
kit/db/transaction.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (c) 2021-2026 Clark Chang. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
|
|
16
|
+
Project: sdpy
|
|
17
|
+
Author: Clark Chang
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# date: 2026-08-23
|
|
21
|
+
"""事务管理模块
|
|
22
|
+
|
|
23
|
+
提供 @transactional 装饰器:捕获 SQLAlchemyError(含 DBError 及其所有子类),
|
|
24
|
+
确保重试逻辑对数据库异常有效。
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import functools
|
|
28
|
+
import inspect
|
|
29
|
+
import time
|
|
30
|
+
from collections.abc import Callable
|
|
31
|
+
from typing import TypeVar
|
|
32
|
+
|
|
33
|
+
from sqlalchemy.exc import SQLAlchemyError
|
|
34
|
+
|
|
35
|
+
from kit.config.log_config import get_default_logger
|
|
36
|
+
from kit.db.exceptions import DBError
|
|
37
|
+
from kit.db.session import session_scope
|
|
38
|
+
|
|
39
|
+
logger = get_default_logger(__name__)
|
|
40
|
+
|
|
41
|
+
F = TypeVar("F", bound=Callable[..., object])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def transactional(
|
|
45
|
+
db_type: str | None = None,
|
|
46
|
+
*,
|
|
47
|
+
retry_count: int = 0,
|
|
48
|
+
retry_delay: float = 0.5,
|
|
49
|
+
) -> Callable[[F], F]:
|
|
50
|
+
"""事务装饰器:自动注入 session,统一捕获 SQLAlchemyError 并重试
|
|
51
|
+
|
|
52
|
+
被装饰的函数必须接受 ``session`` 关键字参数。
|
|
53
|
+
捕获 SQLAlchemyError(含 DBError、IntegrityError、OperationalError 等所有子类)。
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
db_type: 数据库类型,None 时使用配置默认值
|
|
57
|
+
retry_count: 失败后的额外重试次数(0 表示不重试)
|
|
58
|
+
retry_delay: 初始重试延迟(秒),每次重试翻倍(指数退避)
|
|
59
|
+
|
|
60
|
+
用法::
|
|
61
|
+
|
|
62
|
+
@transactional()
|
|
63
|
+
def transfer(session: Session, from_id: int, to_id: int, amount: float):
|
|
64
|
+
# 多个 CRUD 操作在同一事务中
|
|
65
|
+
sender = user_crud.get_or_raise(session, from_id)
|
|
66
|
+
receiver = user_crud.get_or_raise(session, to_id)
|
|
67
|
+
sender.balance -= amount
|
|
68
|
+
receiver.balance += amount
|
|
69
|
+
# 退出时自动提交
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def decorator(func: F) -> F:
|
|
73
|
+
sig = inspect.signature(func)
|
|
74
|
+
|
|
75
|
+
@functools.wraps(func)
|
|
76
|
+
def wrapper(*args: object, **kwargs: object) -> object:
|
|
77
|
+
# 检查函数是否接受 session 参数
|
|
78
|
+
if "session" not in sig.parameters:
|
|
79
|
+
raise TypeError(
|
|
80
|
+
f"被 @transactional 装饰的函数 '{func.__name__}' "
|
|
81
|
+
"必须接受 'session' 关键字参数"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
last_exception: Exception | None = None
|
|
85
|
+
|
|
86
|
+
for attempt in range(retry_count + 1):
|
|
87
|
+
try:
|
|
88
|
+
with session_scope(db_type, autocommit=True) as session:
|
|
89
|
+
kwargs["session"] = session
|
|
90
|
+
return func(*args, **kwargs)
|
|
91
|
+
except SQLAlchemyError as e:
|
|
92
|
+
last_exception = e
|
|
93
|
+
if attempt < retry_count:
|
|
94
|
+
delay = retry_delay * (2**attempt)
|
|
95
|
+
logger.warning(
|
|
96
|
+
f"⚠️ 事务失败,{delay:.1f}s 后重试 "
|
|
97
|
+
f"({attempt + 1}/{retry_count}): {e}"
|
|
98
|
+
)
|
|
99
|
+
time.sleep(delay)
|
|
100
|
+
else:
|
|
101
|
+
break
|
|
102
|
+
|
|
103
|
+
raise DBError(
|
|
104
|
+
f"事务执行失败(重试 {retry_count} 次后仍失败): {last_exception}"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return wrapper # type: ignore
|
|
108
|
+
|
|
109
|
+
return decorator
|