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.
Files changed (54) hide show
  1. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/PKG-INFO +3 -1
  2. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/README.md +2 -0
  3. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/__init__.py +1 -1
  4. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/audit.py +30 -1
  5. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/base_db_kit.py +13 -2
  6. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/.gitignore +0 -0
  7. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/__init__.py +0 -0
  8. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/base_service.py +0 -0
  9. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/chat_service.py +0 -0
  10. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/embedding_service.py +0 -0
  11. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/exceptions.py +0 -0
  12. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/failover.py +0 -0
  13. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/image_service.py +0 -0
  14. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/model_builder.py +0 -0
  15. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/model_client.py +0 -0
  16. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/pool.py +0 -0
  17. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/profiles.py +0 -0
  18. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/rerank_service.py +0 -0
  19. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/runner.py +0 -0
  20. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/ai/types.py +0 -0
  21. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/common_kit.py +0 -0
  22. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/config/__init__.py +0 -0
  23. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/config/kit_config.py +0 -0
  24. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/config/log_config.py +0 -0
  25. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/__init__.py +0 -0
  26. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/article_io.py +0 -0
  27. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/article_models.py +0 -0
  28. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/deepseek_kit.py +0 -0
  29. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/web_article_kit.py +0 -0
  30. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/crawl/wx_article_kit.py +0 -0
  31. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/__init__.py +0 -0
  32. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/crud.py +0 -0
  33. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/engine.py +0 -0
  34. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/exceptions.py +0 -0
  35. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/models/__init__.py +0 -0
  36. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/models/base.py +0 -0
  37. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/mysql_kit.py +0 -0
  38. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/pg_kit.py +0 -0
  39. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/query.py +0 -0
  40. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/session.py +0 -0
  41. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/sqlite_kit.py +0 -0
  42. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/db/transaction.py +0 -0
  43. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/__init__.py +0 -0
  44. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/anydoc_kit.py +0 -0
  45. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/docx_kit.py +0 -0
  46. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/marker_kit.py +0 -0
  47. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/md2doc_kit.py +0 -0
  48. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/mineru_kit.py +0 -0
  49. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/docs/rc_docparser_kit.py +0 -0
  50. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/file_kit.py +0 -0
  51. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/laya_kit.py +0 -0
  52. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/license_kit.py +0 -0
  53. {sdpy_kit-0.6.0 → sdpy_kit-0.6.1}/kit/redis_kit.py +0 -0
  54. {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.0
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` **不**视为未删除,历史数据需自行回填。
@@ -23,7 +23,7 @@ Author: Clark Chang
23
23
  数据库访问通过 kit.db 子包提供(基于 SQLModel)。
24
24
  """
25
25
 
26
- __version__ = "0.6.0"
26
+ __version__ = "0.6.1"
27
27
 
28
28
  from kit.db import (
29
29
  MYSQL,
@@ -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
- if isinstance(columns.get(name), JSON):
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} 没有 updated_at 相关列,无法 touch;"
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