sdpy-kit 0.6.0__tar.gz → 0.6.1__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.
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/PKG-INFO +3 -1
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/README.md +2 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/__init__.py +1 -1
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/audit.py +30 -1
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/base_db_kit.py +13 -2
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/.gitignore +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/__init__.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/base_service.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/chat_service.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/embedding_service.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/exceptions.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/failover.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/image_service.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/model_builder.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/model_client.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/pool.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/profiles.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/rerank_service.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/runner.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/types.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/common_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/config/__init__.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/config/kit_config.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/config/log_config.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/__init__.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/article_io.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/article_models.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/deepseek_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/web_article_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/wx_article_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/__init__.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/crud.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/engine.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/exceptions.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/models/__init__.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/models/base.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/mysql_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/pg_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/query.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/session.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/sqlite_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/transaction.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/__init__.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/anydoc_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/docx_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/marker_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/md2doc_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/mineru_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/rc_docparser_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/file_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/laya_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/license_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/redis_kit.py +0 -0
- {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sdpy-kit
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: SDPY Kit——统一数据库访问层(PG/MySQL/SQLite)与 AI/Redis/文件/文档/向量工具集
|
|
5
5
|
Author-email: Clark <changhongyuan@126.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -662,6 +662,8 @@ AuditConfig.set_fields(None) # 恢复默认
|
|
|
662
662
|
|
|
663
663
|
约定与局限:
|
|
664
664
|
|
|
665
|
+
- `set_fields` 的列名必须是合法标识符(字母 / 数字 / 下划线,不以数字开头),
|
|
666
|
+
否则立即 `ValueError`——列名会被拼进 SQL 的标识符位置。
|
|
665
667
|
- `deleted` 支持整数列(填 `0`)与字符串列(填 `"0"`,`VARCHAR` / `CHAR` / `TEXT`);
|
|
666
668
|
**boolean 列不支持**(会报类型错误)。
|
|
667
669
|
- 查询过滤严格等值 `deleted = 0`(字符串列 `"0"`);`NULL` **不**视为未删除,历史数据需自行回填。
|
|
@@ -586,6 +586,8 @@ AuditConfig.set_fields(None) # 恢复默认
|
|
|
586
586
|
|
|
587
587
|
约定与局限:
|
|
588
588
|
|
|
589
|
+
- `set_fields` 的列名必须是合法标识符(字母 / 数字 / 下划线,不以数字开头),
|
|
590
|
+
否则立即 `ValueError`——列名会被拼进 SQL 的标识符位置。
|
|
589
591
|
- `deleted` 支持整数列(填 `0`)与字符串列(填 `"0"`,`VARCHAR` / `CHAR` / `TEXT`);
|
|
590
592
|
**boolean 列不支持**(会报类型错误)。
|
|
591
593
|
- 查询过滤严格等值 `deleted = 0`(字符串列 `"0"`);`NULL` **不**视为未删除,历史数据需自行回填。
|
|
@@ -68,6 +68,7 @@ UPDATE 不参与 空才填 不参与
|
|
|
68
68
|
AuditConfig.enable(user_resolver=get_current_userid) # 应用启动时调用一次
|
|
69
69
|
"""
|
|
70
70
|
|
|
71
|
+
import re
|
|
71
72
|
import threading
|
|
72
73
|
from collections.abc import Callable, Generator, Mapping, MutableMapping
|
|
73
74
|
from contextlib import contextmanager
|
|
@@ -132,6 +133,23 @@ def _is_empty(value: object) -> bool:
|
|
|
132
133
|
return isinstance(value, str) and not value.strip()
|
|
133
134
|
|
|
134
135
|
|
|
136
|
+
# 列名会被拼进 SQL 的标识符位置(`SET name = :name` / `INSERT ... (name)`),
|
|
137
|
+
# 故配置入口必须与 raw_* 的 data 键同一套白名单,避免手误到写入时才报晦涩错误。
|
|
138
|
+
_IDENT_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _check_field_name(name: object) -> None:
|
|
142
|
+
"""校验配置的列名是合法标识符(拼接进 SQL 前拦截)
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
ValueError: 非字符串 / 空串 / 含字母、数字、下划线以外的字符 / 以数字开头
|
|
146
|
+
"""
|
|
147
|
+
if not isinstance(name, str) or not _IDENT_RE.match(name):
|
|
148
|
+
raise ValueError(
|
|
149
|
+
f"{name!r} 不是合法列名(仅允许字母、数字、下划线,且不能以数字开头)"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
135
153
|
def _is_string_type(column_type: TypeEngine[Any]) -> bool:
|
|
136
154
|
"""是否为字符串列(兼容 SQLModel 的 ``AutoString`` 这类 ``TypeDecorator``)
|
|
137
155
|
|
|
@@ -238,7 +256,8 @@ class AuditConfig:
|
|
|
238
256
|
``deleted``
|
|
239
257
|
|
|
240
258
|
Raises:
|
|
241
|
-
ValueError: 出现未知槽位(防手误,例如把 ``created_at`` 写成 ``create_at
|
|
259
|
+
ValueError: 出现未知槽位(防手误,例如把 ``created_at`` 写成 ``create_at``);
|
|
260
|
+
或列名不是合法标识符(会被拼进 SQL 的标识符位置)
|
|
242
261
|
|
|
243
262
|
用法::
|
|
244
263
|
|
|
@@ -254,6 +273,8 @@ class AuditConfig:
|
|
|
254
273
|
f"未知的字段槽位: {sorted(unknown)};"
|
|
255
274
|
f"可用槽位: {sorted(DEFAULT_FIELDS)}"
|
|
256
275
|
)
|
|
276
|
+
for name in fields.values():
|
|
277
|
+
_check_field_name(name)
|
|
257
278
|
merged.update(fields)
|
|
258
279
|
with cls._lock:
|
|
259
280
|
cls._fields = merged
|
|
@@ -365,6 +386,14 @@ def _candidates(slot: str) -> tuple[str, ...]:
|
|
|
365
386
|
return (primary, *(alias for alias in aliases if alias != primary))
|
|
366
387
|
|
|
367
388
|
|
|
389
|
+
def candidate_columns(slot: str) -> tuple[str, ...]:
|
|
390
|
+
"""槽位的候选列名(当前配置名 + 内置别名),供错误消息与诊断使用
|
|
391
|
+
|
|
392
|
+
⚠ 内部符号(不进 ``kit.db.__all__``)。
|
|
393
|
+
"""
|
|
394
|
+
return _candidates(slot)
|
|
395
|
+
|
|
396
|
+
|
|
368
397
|
def insert_only_columns() -> tuple[str, ...]:
|
|
369
398
|
"""只在 INSERT 填充的列(created_at / created_by 槽位的**全部候选**)
|
|
370
399
|
|
|
@@ -58,7 +58,9 @@ from sqlmodel import Session, SQLModel
|
|
|
58
58
|
from kit.common_kit import CommonKit
|
|
59
59
|
from kit.config.log_config import get_default_logger
|
|
60
60
|
from kit.db.audit import (
|
|
61
|
+
UPDATED_AT,
|
|
61
62
|
AuditConfig,
|
|
63
|
+
candidate_columns,
|
|
62
64
|
deleted_predicate,
|
|
63
65
|
fill_insert_for,
|
|
64
66
|
fill_update,
|
|
@@ -195,7 +197,15 @@ def _adapt_write_values(
|
|
|
195
197
|
data[name] = json.dumps(value, ensure_ascii=False)
|
|
196
198
|
continue
|
|
197
199
|
if isinstance(value, _WRITE_SEQUENCE_TYPES):
|
|
198
|
-
|
|
200
|
+
column_type = columns.get(name)
|
|
201
|
+
if column_type is None:
|
|
202
|
+
raise ValueError(
|
|
203
|
+
f"{name!r} 的值是序列,但表 {table_name} 中查不到该列"
|
|
204
|
+
f"(或列探测失败):请确认表已提交建好;"
|
|
205
|
+
f"JSON 列请传 dict / list;向量请用 to_vector_literal(...);"
|
|
206
|
+
f"数组等其它类型请用 execute() 手写 SQL"
|
|
207
|
+
)
|
|
208
|
+
if isinstance(column_type, JSON):
|
|
199
209
|
data[name] = json.dumps(list(value), ensure_ascii=False)
|
|
200
210
|
else:
|
|
201
211
|
raise ValueError(
|
|
@@ -1000,8 +1010,9 @@ class BaseDbKit(ABC):
|
|
|
1000
1010
|
"或改用 raw_update 显式给字段"
|
|
1001
1011
|
)
|
|
1002
1012
|
if not touch_columns(cls.DB_TYPE, table_name):
|
|
1013
|
+
expected = " / ".join(candidate_columns(UPDATED_AT))
|
|
1003
1014
|
raise DBError(
|
|
1004
|
-
f"表 {table_name} 没有
|
|
1015
|
+
f"表 {table_name} 没有 {expected} 中的任何一列,无法 touch;"
|
|
1005
1016
|
f"请改用 raw_update 显式给字段"
|
|
1006
1017
|
)
|
|
1007
1018
|
|
|
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
|