sqlseed 0.1.16__tar.gz → 0.1.17__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 (70) hide show
  1. {sqlseed-0.1.16 → sqlseed-0.1.17}/CHANGELOG.md +21 -0
  2. {sqlseed-0.1.16 → sqlseed-0.1.17}/CHANGELOG.zh-CN.md +21 -0
  3. {sqlseed-0.1.16 → sqlseed-0.1.17}/PKG-INFO +1 -1
  4. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_utils/progress.py +57 -10
  5. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/orchestrator.py +62 -2
  6. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/_base_adapter.py +12 -0
  7. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/_protocol.py +2 -0
  8. sqlseed-0.1.16/sqlseed-/344/273/243/347/240/201/350/264/250/351/207/217/351/227/256/351/242/230/346/261/207/346/200/273.md +0 -204
  9. {sqlseed-0.1.16 → sqlseed-0.1.17}/.gitignore +0 -0
  10. {sqlseed-0.1.16 → sqlseed-0.1.17}/LICENSE +0 -0
  11. {sqlseed-0.1.16 → sqlseed-0.1.17}/README.md +0 -0
  12. {sqlseed-0.1.16 → sqlseed-0.1.17}/README.zh-CN.md +0 -0
  13. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/build_demo_db.py +0 -0
  14. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/01-quickstart.ipynb +0 -0
  15. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/02-column-mapping.ipynb +0 -0
  16. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/03-generators.ipynb +0 -0
  17. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/04-database-advanced.ipynb +0 -0
  18. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/05-dag-and-constraints.ipynb +0 -0
  19. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/06-config-deep-dive.ipynb +0 -0
  20. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/07-ai-plugin.ipynb +0 -0
  21. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/08-mcp-server.ipynb +0 -0
  22. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/09-plugin-hooks.ipynb +0 -0
  23. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/10-cli-reference.ipynb +0 -0
  24. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/11-utilities.ipynb +0 -0
  25. {sqlseed-0.1.16 → sqlseed-0.1.17}/examples/notebooks/12-testing-patterns.ipynb +0 -0
  26. {sqlseed-0.1.16 → sqlseed-0.1.17}/pyproject.toml +0 -0
  27. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/__init__.py +0 -0
  28. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_utils/__init__.py +0 -0
  29. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_utils/logger.py +0 -0
  30. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_utils/metrics.py +0 -0
  31. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_utils/paths.py +0 -0
  32. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_utils/schema_helpers.py +0 -0
  33. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_utils/sql_safe.py +0 -0
  34. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/_version.py +0 -0
  35. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/cli/__init__.py +0 -0
  36. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/cli/main.py +0 -0
  37. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/config/__init__.py +0 -0
  38. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/config/loader.py +0 -0
  39. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/config/models.py +0 -0
  40. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/config/snapshot.py +0 -0
  41. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/__init__.py +0 -0
  42. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/column_dag.py +0 -0
  43. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/constraints.py +0 -0
  44. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/enrichment.py +0 -0
  45. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/expression.py +0 -0
  46. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/mapper.py +0 -0
  47. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/plugin_mediator.py +0 -0
  48. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/relation.py +0 -0
  49. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/result.py +0 -0
  50. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/schema.py +0 -0
  51. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/transform.py +0 -0
  52. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/core/unique_adjuster.py +0 -0
  53. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/__init__.py +0 -0
  54. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/_compat.py +0 -0
  55. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/_helpers.py +0 -0
  56. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/optimizer.py +0 -0
  57. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/raw_sqlite_adapter.py +0 -0
  58. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/database/sqlite_utils_adapter.py +0 -0
  59. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/__init__.py +0 -0
  60. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/_dispatch.py +0 -0
  61. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/_json_helpers.py +0 -0
  62. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/_protocol.py +0 -0
  63. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/_string_helpers.py +0 -0
  64. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/base_provider.py +0 -0
  65. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/faker_provider.py +0 -0
  66. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/mimesis_provider.py +0 -0
  67. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/registry.py +0 -0
  68. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/generators/stream.py +0 -0
  69. {sqlseed-0.1.16 → sqlseed-0.1.17}/src/sqlseed/py.typed +0 -0
  70. {sqlseed-0.1.16 → sqlseed-0.1.17}/uv.lock +0 -0
@@ -7,6 +7,27 @@ All notable changes to this project will be documented in this file.
7
7
  Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
8
8
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
+ ## [v0.1.17]
11
+
12
+ ### Added
13
+
14
+ - `RichProgressBackend` now accepts `ascii_only` parameter: when `True`, uses `"line"` spinner (`|/-\`) and omits `BarColumn`, avoiding `UnicodeEncodeError` on GBK/Big5/CP936 console encodings
15
+ - `_can_render_unicode()` cached helper probes whether stdout can encode Rich's Braille/block-element characters (U+280B, U+2588, U+2591)
16
+ - `create_progress()` auto-falls back to `ascii_only=True` when `_can_render_unicode()` returns `False`, with a debug log message
17
+ - `DataOrchestrator` adds SQL operation methods: `execute(sql, params)`, `query(sql, params)`, `fetch_one(sql, params)`, `fetch_all(sql, params)` for direct database interaction
18
+ - `BaseSQLiteAdapter._execute(sql, params)` method for parameterized SQL execution
19
+ - `DatabaseAdapter` protocol updated with `_execute` method signature
20
+
21
+ ### Changed
22
+
23
+ - `RichProgressBackend` refresh rate set to 1 Hz (was default 10 Hz) to reduce terminal flicker
24
+ - Test suite: `TestRichProgressBackend` and `TestRichProgressBackendAsciiOnly` merged via `pytest.mark.parametrize` to eliminate code duplication
25
+
26
+ ### Fixed
27
+
28
+ - Windows compatibility: GBK/GB2312/Big5/CP936 encoded terminals no longer crash with `UnicodeEncodeError` when displaying Rich progress bars
29
+ - `.gitignore`: removed `*汇总.md` pattern (no longer needed)
30
+
10
31
  ## [v0.1.16]
11
32
 
12
33
  ### Added
@@ -7,6 +7,27 @@
7
7
  格式基于 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
8
8
  本项目遵循[语义化版本](https://semver.org/spec/v2.0.0.html)。
9
9
 
10
+ ## [v0.1.17]
11
+
12
+ ### 新增
13
+
14
+ - `RichProgressBackend` 新增 `ascii_only` 参数:启用时使用 `"line"` 旋转符(`|/-\`)并省略 `BarColumn`,避免 GBK/Big5/CP936 编码终端的 `UnicodeEncodeError`
15
+ - `_can_render_unicode()` 缓存辅助函数,检测 stdout 是否能编码 Rich 的盲文/方块字符(U+280B, U+2588, U+2591)
16
+ - `create_progress()` 在 `_can_render_unicode()` 返回 `False` 时自动回退到 `ascii_only=True`,并输出 debug 日志
17
+ - `DataOrchestrator` 新增 SQL 操作方法:`execute(sql, params)`、`query(sql, params)`、`fetch_one(sql, params)`、`fetch_all(sql, params)` 用于直接数据库交互
18
+ - `BaseSQLiteAdapter._execute(sql, params)` 参数化 SQL 执行方法
19
+ - `DatabaseAdapter` 协议新增 `_execute` 方法签名
20
+
21
+ ### 变更
22
+
23
+ - `RichProgressBackend` 刷新频率设为 1 Hz(原默认 10 Hz),减少终端闪烁
24
+ - 测试套件:`TestRichProgressBackend` 和 `TestRichProgressBackendAsciiOnly` 通过 `pytest.mark.parametrize` 合并,消除代码重复
25
+
26
+ ### 修复
27
+
28
+ - Windows 兼容性:GBK/GB2312/Big5/CP936 编码终端不再因 Rich 进度条的 Unicode 字符而崩溃
29
+ - `.gitignore`:移除 `*汇总.md` 规则(不再需要)
30
+
10
31
  ## [v0.1.16]
11
32
 
12
33
  ### 新增
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlseed
3
- Version: 0.1.16
3
+ Version: 0.1.17
4
4
  Summary: Declarative SQLite test data generation toolkit
5
5
  Project-URL: Homepage, https://github.com/sunbos/sqlseed
6
6
  Project-URL: Documentation, https://github.com/sunbos/sqlseed#readme
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import sys
3
4
  from abc import ABC, abstractmethod
4
5
  from functools import lru_cache
5
6
  from importlib.util import find_spec
@@ -64,6 +65,24 @@ def _detect_environment() -> RuntimeEnv:
64
65
  return "terminal"
65
66
 
66
67
 
68
+ @lru_cache(maxsize=1)
69
+ def _can_render_unicode() -> bool:
70
+ """Check whether stdout can encode characters used by Rich progress bars.
71
+
72
+ Rich's default ``SpinnerColumn`` uses Braille patterns (e.g. ``⠋`` U+280B)
73
+ and ``BarColumn`` uses block elements (``█`` U+2588, ``░`` U+2591). On
74
+ Windows consoles with GBK / GB2312 / Big5 encodings these characters cause
75
+ ``UnicodeEncodeError``. This helper probes the actual encoding so that
76
+ ``create_progress()`` can fall back to an ASCII-safe layout.
77
+ """
78
+ try:
79
+ encoding = getattr(sys.stdout, "encoding", None) or "utf-8"
80
+ "\u280b\u2588\u2591".encode(encoding)
81
+ return True
82
+ except (UnicodeEncodeError, LookupError, TypeError):
83
+ return False
84
+
85
+
67
86
  # ---------------------------------------------------------------------------
68
87
  # Abstract backend
69
88
  # ---------------------------------------------------------------------------
@@ -130,18 +149,37 @@ class RichProgressBackend(ProgressBackend):
130
149
  """Rich Progress backend for terminal environments.
131
150
 
132
151
  Renders spinner, progress bar, percentage, speed, and ETA.
152
+
153
+ When *ascii_only* is ``True`` the layout avoids Unicode characters
154
+ (Braille spinners, block-element bars) that cannot be encoded by
155
+ limited console encodings such as GBK or Big5. The spinner falls back
156
+ to the ``"line"`` style (``|/-\\``) and the graphical bar is omitted.
133
157
  """
134
158
 
135
- def __init__(self) -> None:
159
+ def __init__(self, *, ascii_only: bool = False) -> None:
160
+ if ascii_only:
161
+ columns: list[Any] = [
162
+ SpinnerColumn("line"),
163
+ TextColumn("[progress.description]{task.description}"),
164
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
165
+ TextColumn("{task.completed}/{task.total}"),
166
+ TransferSpeedColumn(),
167
+ TimeRemainingColumn(),
168
+ ]
169
+ else:
170
+ columns = [
171
+ SpinnerColumn(),
172
+ TextColumn("[progress.description]{task.description}"),
173
+ BarColumn(),
174
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
175
+ TextColumn("{task.completed}/{task.total}"),
176
+ TransferSpeedColumn(),
177
+ TimeRemainingColumn(),
178
+ ]
136
179
  self._progress = Progress(
137
- SpinnerColumn(),
138
- TextColumn("[progress.description]{task.description}"),
139
- BarColumn(),
140
- TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
141
- TextColumn("{task.completed}/{task.total}"),
142
- TransferSpeedColumn(),
143
- TimeRemainingColumn(),
180
+ *columns,
144
181
  transient=False,
182
+ refresh_per_second=1,
145
183
  )
146
184
 
147
185
  def __enter__(self) -> RichProgressBackend:
@@ -258,11 +296,17 @@ def create_progress(*, disable: bool = False) -> ProgressBackend:
258
296
  disable=True → NullProgressBackend (zero-cost no-op)
259
297
  Jupyter+tqdm → TqdmNotebookBackend (native notebook widget)
260
298
  Jupyter-tqdm → NullProgressBackend (graceful degradation)
261
- Terminal → RichProgressBackend (rich spinner + bar)
299
+ Terminal+UTF8 → RichProgressBackend (rich spinner + bar)
300
+ Terminal+GBK → RichProgressBackend(ascii_only=True) (ASCII spinner, no bar)
262
301
 
263
302
  The Jupyter-without-tqdm path logs a one-time warning instead of raising
264
303
  ImportError, because progress display is a UX nicety, not a correctness
265
304
  requirement.
305
+
306
+ When the console encoding cannot represent the Unicode characters used by
307
+ Rich's default spinner (Braille patterns) and bar (block elements), the
308
+ factory automatically switches to an ASCII-safe layout so that Windows
309
+ consoles with GBK / Big5 encodings do not crash with ``UnicodeEncodeError``.
266
310
  """
267
311
  if disable:
268
312
  return NullProgressBackend()
@@ -277,4 +321,7 @@ def create_progress(*, disable: bool = False) -> ProgressBackend:
277
321
  )
278
322
  return NullProgressBackend()
279
323
 
280
- return RichProgressBackend()
324
+ ascii_only = not _can_render_unicode()
325
+ if ascii_only:
326
+ logger.debug("Console encoding does not support Unicode progress characters — using ASCII-safe layout")
327
+ return RichProgressBackend(ascii_only=ascii_only)
@@ -387,8 +387,6 @@ class DataOrchestrator:
387
387
 
388
388
  except (ValueError, RuntimeError, OSError, sqlite3.OperationalError, sqlite3.IntegrityError) as e:
389
389
  if isinstance(e, sqlite3.IntegrityError) and enrich:
390
- # enrich mode: UNIQUE conflicts are expected when merging
391
- # into tables that already contain data
392
390
  logger.warning("Integrity constraint during enrich", table_name=table_name, error=e)
393
391
  else:
394
392
  logger.error("Failed to fill table", table_name=table_name, error=e)
@@ -550,6 +548,68 @@ class DataOrchestrator:
550
548
 
551
549
  fill = fill_table
552
550
 
551
+ def execute(self, sql: str, params: tuple[Any, ...] | None = None) -> Any:
552
+ """Execute a SQL statement.
553
+
554
+ Args:
555
+ sql: The SQL statement to execute.
556
+ params: Optional tuple of parameters for parameterized queries.
557
+
558
+ Returns:
559
+ A cursor object with the result.
560
+ """
561
+ self._ensure_connected()
562
+ if params is None:
563
+ params = ()
564
+ return self._db._execute(sql, params)
565
+
566
+ def query(self, sql: str, params: tuple[Any, ...] | None = None) -> list[dict[str, Any]]:
567
+ """Execute a SELECT query and return results as a list of dictionaries.
568
+
569
+ Args:
570
+ sql: The SQL SELECT query to execute.
571
+ params: Optional tuple of parameters for parameterized queries.
572
+
573
+ Returns:
574
+ A list of dictionaries, where each dictionary represents a row.
575
+ """
576
+ self._ensure_connected()
577
+ cursor = self.execute(sql, params)
578
+ columns = [desc[0] for desc in cursor.description]
579
+ return [dict(zip(columns, row, strict=True)) for row in cursor.fetchall()]
580
+
581
+ def fetch_one(self, sql: str, params: tuple[Any, ...] | None = None) -> dict[str, Any] | None:
582
+ """Execute a SELECT query and return a single row as a dictionary.
583
+
584
+ Args:
585
+ sql: The SQL SELECT query to execute.
586
+ params: Optional tuple of parameters for parameterized queries.
587
+
588
+ Returns:
589
+ A dictionary representing the first row, or None if no rows found.
590
+ """
591
+ self._ensure_connected()
592
+ cursor = self.execute(sql, params)
593
+ row = cursor.fetchone()
594
+ if row is None:
595
+ return None
596
+ columns = [desc[0] for desc in cursor.description]
597
+ return dict(zip(columns, row, strict=True))
598
+
599
+ def fetch_all(self, sql: str, params: tuple[Any, ...] | None = None) -> list[Any]:
600
+ """Execute a SELECT query and return results as a list of lists.
601
+
602
+ Args:
603
+ sql: The SQL SELECT query to execute.
604
+ params: Optional tuple of parameters for parameterized queries.
605
+
606
+ Returns:
607
+ A list of rows, where each row is a list of values.
608
+ """
609
+ self._ensure_connected()
610
+ cursor = self.execute(sql, params)
611
+ return cursor.fetchall() # type: ignore[no-any-return]
612
+
553
613
  def close(self) -> None:
554
614
  if self._connected:
555
615
  self._db.close()
@@ -31,6 +31,18 @@ class BaseSQLiteAdapter:
31
31
  def _get_execute_fn(self) -> Callable[..., Any]:
32
32
  raise NotImplementedError
33
33
 
34
+ def _execute(self, sql: str, params: tuple[Any, ...] = ()) -> Any:
35
+ """Execute a SQL statement with parameters.
36
+
37
+ Args:
38
+ sql: The SQL statement to execute.
39
+ params: Tuple of parameters for parameterized queries.
40
+
41
+ Returns:
42
+ The cursor object.
43
+ """
44
+ return self._get_execute_fn()(sql, params)
45
+
34
46
  def get_column_info(self, table_name: str) -> list[ColumnInfo]:
35
47
  raise NotImplementedError
36
48
 
@@ -67,6 +67,8 @@ class DatabaseAdapter(Protocol):
67
67
 
68
68
  def restore_settings(self) -> None: ...
69
69
 
70
+ def _execute(self, sql: str, params: tuple[Any, ...] = ()) -> Any: ...
71
+
70
72
  def __enter__(self) -> DatabaseAdapter: ...
71
73
 
72
74
  def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any) -> None: ...
@@ -1,204 +0,0 @@
1
- # sqlseed 项目代码质量问题汇总
2
-
3
- > **项目**:`sunbos/sqlseed`
4
- > **生成日期**:2026-05-07
5
- > **Commit 链**:`91a30c2b` → `b2a367e0` → `eaab405a`
6
-
7
- ---
8
-
9
- ## 一、SonarCloud 安全漏洞汇总(Commit 91a30c2b 之前)
10
-
11
- **来源**:[SonarCloud Issues](https://sonarcloud.io/project/issues?severities=BLOCKER%2CCRITICAL%2CMAJOR%2CMINOR&sinceLeakPeriod=true&issueStatuses=OPEN%2CCONFIRMED&types=VULNERABILITY&id=sunbos_sqlseed)
12
-
13
- **统计**:共 **3 个** Vulnerability,全部为 Major 级别
14
-
15
- | # | 文件 | 规则 | 严重级别 | 安全影响 | 状态 |
16
- |---|------|------|---------|---------|------|
17
- | 1 | `plugins/mcp-server-sqlseed/pyproject.toml` | S8565 | Major | Security - Medium | ✅ 已修复 |
18
- | 2 | `plugins/sqlseed-ai/pyproject.toml` | S8565 | Major | Security - Medium | ✅ 已修复 |
19
- | 3 | `pyproject.toml`(根目录) | S8565 | Major | Security - Medium | ✅ 已修复 |
20
-
21
- > **修复方式**:Commit `b2a367e0` 中已为所有 3 个 `pyproject.toml` 生成了 `uv.lock` 文件。
22
-
23
- ---
24
-
25
- ## 二、SonarCloud 代码质量问题汇总(最新状态)
26
-
27
- **来源**:[SonarCloud Issues](https://sonarcloud.io/project/issues?issueStatuses=OPEN%2CCONFIRMED&sinceLeakPeriod=true&id=sunbos_sqlseed)
28
-
29
- **统计**:共 **11 个问题**(4 高级 + 7 中级),分布在 2 个维度
30
-
31
- ### 2.1 按维度和严重级别分布
32
-
33
- | 维度 | 严重级别 | 数量 | 类型 |
34
- |------|---------|------|------|
35
- | Reliability | High (Medium impact) | 7 | **Bug** |
36
- | Maintainability | High (High impact) | 4 | Code Smell |
37
-
38
- ### 2.2 按文件分布
39
-
40
- | 文件 | Bug | Code Smell | 合计 |
41
- |------|-----|------------|------|
42
- | `examples/notebooks/01-quickstart.ipynb` | 5 | 0 | 5 |
43
- | `examples/notebooks/05-dag-and-constraints.ipynb` | 0 | 1 | 1 |
44
- | `examples/notebooks/06-config-deep-dive.ipynb` | 0 | 2 | 2 |
45
- | `examples/notebooks/07-ai-plugin.ipynb` | 0 | 1 | 1 |
46
- | `examples/notebooks/09-plugin-hooks.ipynb` | 2 | 0 | 2 |
47
-
48
- ### 2.3 详细问题列表
49
-
50
- #### 高级问题(Maintainability High)— 共 4 个 Code Smell
51
-
52
- | # | 文件 | 行号 | 描述 | 修复工作量 |
53
- |---|------|------|------|-----------|
54
- | 1 | `05-dag-and-constraints.ipynb` | L293 | 字符串字面量 `"PRJ-\\d{6}"` 重复 3 次,应定义为常量 | 6min |
55
- | 2 | `06-config-deep-dive.ipynb` | L755 | 字符串字面量 `"ORG-\\d{4}"` 重复 4 次,应定义为常量 | 8min |
56
- | 3 | `06-config-deep-dive.ipynb` | L756 | 字符串字面量 `"ORG-\\d{4}"` 重复 3 次,应定义为常量 | 6min |
57
- | 4 | `07-ai-plugin.ipynb` | L330 | 字符串字面量 `"ORG-\\d{4}"` 重复 3 次,应定义为常量 | 6min |
58
-
59
- #### 中级问题(Reliability Medium)— 共 7 个 Bug
60
-
61
- | # | 文件 | 行号 | 描述 | 修复工作量 |
62
- |---|------|------|------|-----------|
63
- | 1 | `01-quickstart.ipynb` | L428 | 无效的自我赋值 `PRJ_PATTERN = PRJ_PATTERN` | 3min |
64
- | 2 | `01-quickstart.ipynb` | L571 | 无效的自我赋值 `ORG_PATTERN = ORG_PATTERN` | 3min |
65
- | 3 | `01-quickstart.ipynb` | L858 | 无效的自我赋值 `ORG_PATTERN = ORG_PATTERN` | 3min |
66
- | 4 | `01-quickstart.ipynb` | L864 | 无效的自我赋值 `ORG_PATTERN = ORG_PATTERN` | 3min |
67
- | 5 | `01-quickstart.ipynb` | L1095 | 无效的自我赋值 `COUNT_ORG_SQL = COUNT_ORG_SQL` | 3min |
68
- | 6 | `09-plugin-hooks.ipynb` | L386 | 无效的自我赋值 `ORG_PATTERN = ORG_PATTERN` | 3min |
69
- | 7 | `09-plugin-hooks.ipynb` | L467 | 无效的自我赋值 `ORG_PATTERN = ORG_PATTERN` | 3min |
70
-
71
- > **根因分析**:这 7 个 Bug 是 Commit `eaab405a` 中引入的。在将重复字符串提取为常量时,notebook 的单元格中出现了 `PRJ_PATTERN = PRJ_PATTERN` 这样的自我赋值(notebook 中常量定义在之前的单元格,当前单元格重新赋值是冗余的)。**应删除这些冗余的赋值语句**。
72
-
73
- ---
74
-
75
- ## 三、CodeFlow 分析汇总 — Commit eaab405a(最新)
76
-
77
- **来源**:[CodeFlow - Commit eaab405a](https://app.getcodeflow.com/github/sunbos/sqlseed/commits/eaab405a1f7bf74e6e7aac9b74a1b7092fa5eedf)
78
-
79
- **Commit**:`chore: additional code quality and documentation improvements`
80
-
81
- **统计**:共 **9 个警示**(0 个错误)
82
-
83
- ### 3.1 按文件分布
84
-
85
- | 文件 | 错误 | 警示 | 合计 |
86
- |------|------|------|------|
87
- | `src/sqlseed/_utils/progress.py` | 0 | 6 | 6 |
88
- | `tests/test_utils/test_progress.py` | 0 | 3 | 3 |
89
-
90
- ### 3.2 按问题类型分布
91
-
92
- | 问题类型 | 数量 | 说明 |
93
- |---------|------|------|
94
- | `unnecessary-pass` | 3 | 方法体中不必要的 `pass` 语句 |
95
- | `wrong-import-position` | 3 | import 语句位置不符合 PEP 8 |
96
- | `import-outside-toplevel` | 2 | import 不在模块顶层 |
97
- | `global-statement` | 1 | 使用了 global 语句 |
98
-
99
- ### 3.3 详细问题列表
100
-
101
- #### 文件 1:`src/sqlseed/_utils/progress.py`(0 错误 / 6 警示)
102
-
103
- | # | 行号 | 规则 | 描述 | 代码 |
104
- |---|------|------|------|------|
105
- | 1 | 105 | `unnecessary-pass` | 方法体中不必要的 `pass` | `def __enter__(self) -> TqdmNotebookBackend: ... pass` |
106
- | 2 | 113 | `unnecessary-pass` | 方法体中不必要的 `pass` | `def __exit__(self, *args: Any) -> None: ... pass` |
107
- | 3 | 117 | `unnecessary-pass` | 方法体中不必要的 `pass` | `def add_task(...): ... pass` |
108
- | 4 | 201 | `import-outside-toplevel` | import 不在模块顶层 | `from tqdm.auto import tqdm` |
109
- | 5 | 246 | `global-statement` | 使用了 global 语句 | `global _HAS_TQDM` |
110
- | 6 | — | `import-outside-toplevel` | import 不在模块顶层 | 延迟导入相关 |
111
-
112
- > **说明**:Commit `eaab405a` 为 `NullProgressBackend` 的空方法添加了 docstring(如 `"""Enter the progress context."""`),但方法体仍包含 `pass` 语句。由于已有 docstring,`pass` 是多余的。
113
-
114
- #### 文件 2:`tests/test_utils/test_progress.py`(0 错误 / 3 警示)
115
-
116
- | # | 行号 | 规则 | 描述 | 代码 |
117
- |---|------|------|------|------|
118
- | 1 | 11 | `wrong-import-position` | `import pytest` 应放在模块顶部 | `import pytest` |
119
- | 2 | 13 | `wrong-import-position` | `import sqlseed._utils.progress` 应放在模块顶部 | `import sqlseed._utils.progress as progress_mod` |
120
- | 3 | 14 | `wrong-import-position` | `from sqlseed._utils.progress import (...)` 应放在模块顶部 | `from sqlseed._utils.progress import NullProgressBackend, ...` |
121
-
122
- > **说明**:这些 import 被放在 `if TYPE_CHECKING:` 块之后,违反了 PEP 8 的 import 排序规范。应将它们移到 `TYPE_CHECKING` 块之前。
123
-
124
- ### 3.4 修复建议
125
-
126
- | 优先级 | 问题 | 建议 |
127
- |--------|------|------|
128
- | **P1** | `unnecessary-pass` × 3 | 删除 `progress.py` 中行 105、113、117 的 `pass` 语句(已有 docstring,pass 多余) |
129
- | **P1** | `wrong-import-position` × 3 | 将 `test_progress.py` 中行 11、13-22 的 import 移到 `if TYPE_CHECKING:` 块之前 |
130
- | **P3** | `import-outside-toplevel` × 2 | 延迟加载是有意设计,已有 `# noqa` 注释,建议配置忽略 |
131
- | **P3** | `global-statement` × 1 | 缓存模式的有意使用,建议配置忽略 |
132
-
133
- ---
134
-
135
- ## 四、历史问题修复记录
136
-
137
- ### Commit b2a367e0 修复的问题
138
-
139
- | # | 来源 | 文件 | 问题 | 修复方式 |
140
- |---|------|------|------|---------|
141
- | 1 | SonarCloud | 3× `pyproject.toml` | S8565 缺少锁文件 | 生成 `uv.lock` |
142
- | 2 | CodeFlow | `models.py:75` | `no-member` 错误 | `cls.model_fields.keys()` → `cls.model_fields` |
143
- | 3 | CodeFlow | `_model_selector.py:28` | `broad-exception-caught` | 缩窄为具体异常类型 |
144
- | 4 | CodeFlow | `progress.py` | 4× `disallowed-name` "bar" | 改为 `pbar` |
145
- | 5 | CodeFlow | `stream.py` | 2× `try-except-raise` | 移除冗余 except 块 |
146
- | 6 | CodeFlow | `stream.py:91` | `unused-variable` | `_retry_i` → `_` |
147
- | 7 | CodeFlow | `test_cli.py` | 2× `CodeDuplication` | 提取公共 fixture |
148
-
149
- ### Commit eaab405a 修复的问题
150
-
151
- | # | 来源 | 文件 | 问题 | 修复方式 |
152
- |---|------|------|------|---------|
153
- | 8 | SonarCloud | `01-quickstart.ipynb` | 字符串 `"SELECT COUNT(*) FROM organizations"` 重复 | 提取为 `COUNT_ORG_SQL` 常量 |
154
- | 9 | SonarCloud | `01-quickstart.ipynb` | 字符串 `"SELECT org_code FROM organizations"` 重复 | 复用 `COUNT_ORG_SQL` |
155
- | 10 | SonarCloud | `progress.py:103,109` | 2× 空方法体 | 添加 docstring |
156
- | 11 | SonarCloud | `cli/main.py:263` | 认知复杂度过高 | 提取外键打印逻辑 |
157
- | 12 | SonarCloud | `test_progress.py:265` | yield 缺少 Generator 类型标注 | 添加类型标注 |
158
- | 13 | SonarCloud | `models.py:79` | 不必要的 `list()` 调用 | 简化字典迭代 |
159
- | 14 | SonarCloud | `_model_selector.py:29` | 冗余 Exception 子类 | 移除 `OSError` |
160
- | 15 | SonarCloud | `04-database-advanced.ipynb` | 2× set 构造优化 | 改为集合推导式 |
161
- | 16 | CodeFlow | `_model_selector.py:29` | `overlapping-except` | 移除 `OSError` |
162
-
163
- ### Commit eaab405a 新引入的问题
164
-
165
- | # | 来源 | 文件 | 问题 | 原因 |
166
- |---|------|------|------|------|
167
- | 1 | SonarCloud | `01-quickstart.ipynb` | 5× useless self-assignment | 常量定义在 notebook 前一个单元格,当前单元格冗余赋值 |
168
- | 2 | SonarCloud | `09-plugin-hooks.ipynb` | 2× useless self-assignment | 同上 |
169
- | 3 | CodeFlow | `progress.py` | 3× `unnecessary-pass` | 添加 docstring 后未删除多余的 `pass` |
170
- | 4 | CodeFlow | `test_progress.py` | 3× `wrong-import-position` | import 排在 `TYPE_CHECKING` 块之后 |
171
-
172
- ---
173
-
174
- ## 五、综合修复优先级建议
175
-
176
- ### P0 — 必须修复(Bug / 影响正确性)
177
-
178
- | # | 文件 | 问题 | 数量 | 预计工作量 |
179
- |---|------|------|------|-----------|
180
- | 1 | `01-quickstart.ipynb` | useless self-assignment | 5 | 15min |
181
- | 2 | `09-plugin-hooks.ipynb` | useless self-assignment | 2 | 6min |
182
-
183
- > **修复方式**:删除 notebook 单元格中冗余的 `PRJ_PATTERN = PRJ_PATTERN`、`ORG_PATTERN = ORG_PATTERN`、`COUNT_ORG_SQL = COUNT_ORG_SQL` 等自我赋值语句。
184
-
185
- ### P1 — 建议尽快修复(代码规范)
186
-
187
- | # | 文件 | 问题 | 数量 | 预计工作量 |
188
- |---|------|------|------|-----------|
189
- | 3 | `progress.py` | `unnecessary-pass` | 3 | 3min |
190
- | 4 | `test_progress.py` | `wrong-import-position` | 3 | 5min |
191
- | 5 | 4× notebooks | 字符串字面量重复 | 4 | 26min |
192
-
193
- ### P2 — 建议修复(可维护性)
194
-
195
- | # | 文件 | 问题 | 数量 |
196
- |---|------|------|------|
197
- | 6 | `progress.py` | `import-outside-toplevel` + `global-statement` | 3 |
198
-
199
- ### P3 — 可选(有意设计,建议配置忽略)
200
-
201
- | # | 文件 | 问题 | 说明 |
202
- |---|------|------|------|
203
- | 7 | `progress.py` | `import-outside-toplevel` | tqdm 延迟加载 |
204
- | 8 | `progress.py` | `global-statement` | `_HAS_TQDM` 缓存标记 |
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes