dclassql 0.2.0__tar.gz → 0.3.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.
- {dclassql-0.2.0 → dclassql-0.3.1}/PKG-INFO +2 -2
- {dclassql-0.2.0 → dclassql-0.3.1}/README.md +1 -1
- {dclassql-0.2.0 → dclassql-0.3.1}/pyproject.toml +3 -3
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/__init__.py +2 -2
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/cli.py +0 -46
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/client.py +608 -74
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/codegen.py +25 -50
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/model_inspector.py +1 -1
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/backends/base.py +5 -4
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/backends/protocols.py +7 -4
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/backends/where_compiler.py +39 -5
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/sqlite_adapters.py +0 -3
- dclassql-0.3.1/src/dclassql/templates/partials/client_class.jinja +66 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/partials/imports.jinja +5 -3
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/partials/model_section.jinja +5 -5
- dclassql-0.2.0/src/dclassql/generated_models/__init__.py +0 -0
- dclassql-0.2.0/src/dclassql/generated_models/test_models.py +0 -78
- dclassql-0.2.0/src/dclassql/templates/partials/client_class.jinja +0 -32
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/.gitignore +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/asdict.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/asdict.pyi +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/db_pool.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/push/__init__.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/push/base.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/push/sqlite.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/backends/__init__.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/backends/lazy.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/backends/metadata.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/backends/sqlite.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/datasource.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/runtime/sql_recorder.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/table_spec.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/__init__.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/asdict_stub.pyi.jinja +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/client_module.py.jinja +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/partials/exports.jinja +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/partials/macros.jinja +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/templates/partials/scalar_filters.jinja +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/typing.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/unwarp.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/utils/__init__.py +0 -0
- {dclassql-0.2.0 → dclassql-0.3.1}/src/dclassql/utils/ensure.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: dclassql
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: A type-safe ORM generator for Python, creating fully type-hinted database clients from plain dataclass definitions.
|
|
5
5
|
Keywords: orm,codegen,sqlite,dataclass,typed
|
|
6
6
|
Author: myuanz
|
|
@@ -86,7 +86,7 @@ uv add dclassql
|
|
|
86
86
|
|
|
87
87
|
## 当前状态
|
|
88
88
|
|
|
89
|
-
DataclassQL 仍在早期开发阶段,
|
|
89
|
+
DataclassQL 仍在早期开发阶段, 但不是无根浮萍, 我已经在另外两个项目里大量使用, 目前基于其他项目的反馈来更新.
|
|
90
90
|
|
|
91
91
|
## 一份更长的例子
|
|
92
92
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dclassql"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.1"
|
|
4
4
|
description = "A type-safe ORM generator for Python, creating fully type-hinted database clients from plain dataclass definitions."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -26,10 +26,10 @@ dependencies = [
|
|
|
26
26
|
]
|
|
27
27
|
|
|
28
28
|
[project.scripts]
|
|
29
|
-
"
|
|
29
|
+
"dclassql" = "dclassql.cli:main"
|
|
30
30
|
|
|
31
31
|
[build-system]
|
|
32
|
-
requires = ["uv_build>=0.
|
|
32
|
+
requires = ["uv_build>=0.11.6,<0.12.0"]
|
|
33
33
|
build-backend = "uv_build"
|
|
34
34
|
|
|
35
35
|
[dependency-groups]
|
|
@@ -10,12 +10,12 @@ from .unwarp import unwarp, unwarp_or, unwarp_or_raise
|
|
|
10
10
|
class _MissingClient:
|
|
11
11
|
def __init__(self, *args: object, **kwargs: object) -> None:
|
|
12
12
|
raise RuntimeError(
|
|
13
|
-
"dclassql.Client 尚未生成。请先运行 `
|
|
13
|
+
"dclassql.Client 尚未生成。请先运行 `dclassql -m <model.py> generate` 生成客户端后再导入。"
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
try: # pragma: no cover - exercised in integration tests
|
|
17
17
|
from .client import Client # type: ignore
|
|
18
|
-
except ModuleNotFoundError: # pragma: no cover - fallback when未生成
|
|
18
|
+
except (ModuleNotFoundError, ImportError): # pragma: no cover - fallback when未生成
|
|
19
19
|
Client = _MissingClient # type: ignore[assignment]
|
|
20
20
|
|
|
21
21
|
|
|
@@ -3,9 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import argparse
|
|
4
4
|
import importlib.util
|
|
5
5
|
import re
|
|
6
|
-
import shutil
|
|
7
6
|
import sys
|
|
8
|
-
import warnings
|
|
9
7
|
from pathlib import Path
|
|
10
8
|
from types import ModuleType
|
|
11
9
|
from typing import Any, Callable, Literal, Sequence
|
|
@@ -19,7 +17,6 @@ from .runtime.datasource import open_sqlite_connection
|
|
|
19
17
|
|
|
20
18
|
DEFAULT_MODEL_FILE = "model.py"
|
|
21
19
|
GENERATED_CLIENT_FILENAME = "client.py"
|
|
22
|
-
GENERATED_MODELS_DIRNAME = "generated_models"
|
|
23
20
|
|
|
24
21
|
ConfirmRebuildMode = Literal["auto", "prompt"]
|
|
25
22
|
ConfirmCallback = Callable[
|
|
@@ -77,43 +74,6 @@ def resolve_asdict_stub_path() -> Path:
|
|
|
77
74
|
return _find_package_directory() / "asdict.pyi"
|
|
78
75
|
|
|
79
76
|
|
|
80
|
-
def resolve_models_directory() -> Path:
|
|
81
|
-
return _find_package_directory() / GENERATED_MODELS_DIRNAME
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def _sanitize_name(name: str) -> str:
|
|
85
|
-
sanitized = re.sub(r"[^0-9a-zA-Z_]+", "_", name).strip("_")
|
|
86
|
-
return sanitized.lower() or "models"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def compute_model_target(module_path: Path) -> tuple[Path, str]:
|
|
90
|
-
base_dir = resolve_models_directory()
|
|
91
|
-
base_dir.mkdir(parents=True, exist_ok=True)
|
|
92
|
-
(base_dir / "__init__.py").touch()
|
|
93
|
-
|
|
94
|
-
module_name = _sanitize_name(module_path.stem)
|
|
95
|
-
|
|
96
|
-
target_path = base_dir / f"{module_name}.py"
|
|
97
|
-
import_path = f"dclassql.{GENERATED_MODELS_DIRNAME}.{module_name}"
|
|
98
|
-
return target_path, import_path
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def materialize_model_module(module_path: Path) -> str:
|
|
102
|
-
target_path, import_path = compute_model_target(module_path)
|
|
103
|
-
if target_path.exists() or target_path.is_symlink():
|
|
104
|
-
target_path.unlink()
|
|
105
|
-
try:
|
|
106
|
-
target_path.symlink_to(module_path.resolve())
|
|
107
|
-
except OSError as exc:
|
|
108
|
-
warnings.warn(
|
|
109
|
-
f"Unable to create symlink for model '{module_path}'; falling back to copy. ({exc})",
|
|
110
|
-
RuntimeWarning,
|
|
111
|
-
stacklevel=2,
|
|
112
|
-
)
|
|
113
|
-
shutil.copy2(module_path, target_path)
|
|
114
|
-
return import_path
|
|
115
|
-
|
|
116
|
-
|
|
117
77
|
def collect_models(module: ModuleType) -> list[type[Any]]:
|
|
118
78
|
from dataclasses import is_dataclass
|
|
119
79
|
|
|
@@ -205,13 +165,7 @@ def push_database(
|
|
|
205
165
|
def command_generate(module_path: Path) -> None:
|
|
206
166
|
module = load_module(module_path)
|
|
207
167
|
models = collect_models(module)
|
|
208
|
-
generated_models_module = materialize_model_module(module_path)
|
|
209
|
-
original_modules = {model: model.__module__ for model in models}
|
|
210
|
-
for model in models:
|
|
211
|
-
model.__module__ = generated_models_module
|
|
212
168
|
generated = generate_client(models)
|
|
213
|
-
for model, original in original_modules.items():
|
|
214
|
-
model.__module__ = original
|
|
215
169
|
output_path = resolve_generated_path()
|
|
216
170
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
217
171
|
output_path.write_text(generated.code, encoding="utf-8")
|