etlantic-sqlmodel 0.14.0__tar.gz → 0.19.0__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.
- {etlantic_sqlmodel-0.14.0 → etlantic_sqlmodel-0.19.0}/.gitignore +2 -0
- {etlantic_sqlmodel-0.14.0 → etlantic_sqlmodel-0.19.0}/PKG-INFO +5 -5
- {etlantic_sqlmodel-0.14.0 → etlantic_sqlmodel-0.19.0}/README.md +2 -2
- {etlantic_sqlmodel-0.14.0 → etlantic_sqlmodel-0.19.0}/pyproject.toml +3 -3
- {etlantic_sqlmodel-0.14.0 → etlantic_sqlmodel-0.19.0}/src/etlantic_sqlmodel/__init__.py +95 -1
- {etlantic_sqlmodel-0.14.0 → etlantic_sqlmodel-0.19.0}/src/etlantic_sqlmodel/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: etlantic-sqlmodel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.0
|
|
4
4
|
Summary: ContractModel ↔ SQLModel bridge for ETLantic.
|
|
5
5
|
Project-URL: Homepage, https://github.com/eddiethedean/etlantic
|
|
6
6
|
Project-URL: Documentation, https://github.com/eddiethedean/etlantic/tree/main/docs
|
|
@@ -9,7 +9,7 @@ Project-URL: Issues, https://github.com/eddiethedean/etlantic/issues
|
|
|
9
9
|
Project-URL: Changelog, https://github.com/eddiethedean/etlantic/blob/main/CHANGELOG.md
|
|
10
10
|
Author-email: Odo Matthews <odosmatthews@gmail.com>
|
|
11
11
|
License-Expression: MIT
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -18,17 +18,17 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
19
|
Classifier: Typing :: Typed
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
|
-
Requires-Dist: etlantic<0.
|
|
21
|
+
Requires-Dist: etlantic<0.20,>=0.19.0
|
|
22
22
|
Requires-Dist: sqlmodel<1,>=0.0.22
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
25
25
|
# etlantic-sqlmodel
|
|
26
26
|
|
|
27
27
|
Optional bridge between ETLantic `Data` contracts and
|
|
28
|
-
[SQLModel](https://sqlmodel.tiangolo.com/) table models for ETLantic 0.
|
|
28
|
+
[SQLModel](https://sqlmodel.tiangolo.com/) table models for ETLantic 0.19.
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
pip install 'etlantic==0.
|
|
31
|
+
pip install 'etlantic==0.19.0' 'etlantic-sqlmodel==0.19.0'
|
|
32
32
|
# or: pip install 'etlantic[sqlmodel]'
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# etlantic-sqlmodel
|
|
2
2
|
|
|
3
3
|
Optional bridge between ETLantic `Data` contracts and
|
|
4
|
-
[SQLModel](https://sqlmodel.tiangolo.com/) table models for ETLantic 0.
|
|
4
|
+
[SQLModel](https://sqlmodel.tiangolo.com/) table models for ETLantic 0.19.
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
|
-
pip install 'etlantic==0.
|
|
7
|
+
pip install 'etlantic==0.19.0' 'etlantic-sqlmodel==0.19.0'
|
|
8
8
|
# or: pip install 'etlantic[sqlmodel]'
|
|
9
9
|
```
|
|
10
10
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "etlantic-sqlmodel"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.19.0"
|
|
4
4
|
description = "ContractModel ↔ SQLModel bridge for ETLantic."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
requires-python = ">=3.11"
|
|
8
8
|
authors = [{ name = "Odo Matthews", email = "odosmatthews@gmail.com" }]
|
|
9
9
|
classifiers = [
|
|
10
|
-
"Development Status ::
|
|
10
|
+
"Development Status :: 5 - Production/Stable",
|
|
11
11
|
"Intended Audience :: Developers",
|
|
12
12
|
"License :: OSI Approved :: MIT License",
|
|
13
13
|
"Programming Language :: Python :: 3",
|
|
@@ -17,7 +17,7 @@ classifiers = [
|
|
|
17
17
|
"Typing :: Typed",
|
|
18
18
|
]
|
|
19
19
|
dependencies = [
|
|
20
|
-
"etlantic>=0.
|
|
20
|
+
"etlantic>=0.19.0,<0.20",
|
|
21
21
|
"sqlmodel>=0.0.22,<1",
|
|
22
22
|
]
|
|
23
23
|
|
|
@@ -20,13 +20,14 @@ from etlantic.schema_drift import (
|
|
|
20
20
|
)
|
|
21
21
|
from sqlmodel import Field, SQLModel
|
|
22
22
|
|
|
23
|
-
__version__ = "0.
|
|
23
|
+
__version__ = "0.19.0"
|
|
24
24
|
|
|
25
25
|
__all__ = [
|
|
26
26
|
"SqlModelIntegrationPlugin",
|
|
27
27
|
"__version__",
|
|
28
28
|
"compare_metadata",
|
|
29
29
|
"contract_to_sqlmodel",
|
|
30
|
+
"contract_to_sqlmodel_source",
|
|
30
31
|
"create_plugin",
|
|
31
32
|
"run_conformance_checks",
|
|
32
33
|
"sqlmodel_to_contract",
|
|
@@ -82,6 +83,99 @@ def contract_to_sqlmodel(
|
|
|
82
83
|
return SQLModelMetaclass(model_name, (SQLModel,), attrs, table=True)
|
|
83
84
|
|
|
84
85
|
|
|
86
|
+
def contract_to_sqlmodel_source(
|
|
87
|
+
contract_cls: type[Data],
|
|
88
|
+
*,
|
|
89
|
+
table_name: str | None = None,
|
|
90
|
+
primary_key: tuple[str, ...] | None = None,
|
|
91
|
+
) -> str:
|
|
92
|
+
"""Generate importable SQLModel source for a ``Data`` / ContractModel class."""
|
|
93
|
+
if not is_data_contract_type(contract_cls):
|
|
94
|
+
raise TypeError("Expected a Data / ContractModel subclass")
|
|
95
|
+
|
|
96
|
+
resolved_table = table_name or _default_table_name(contract_cls)
|
|
97
|
+
pk_fields = set(primary_key or ())
|
|
98
|
+
model_name = f"{contract_cls.__name__}Table"
|
|
99
|
+
imports: set[str] = set()
|
|
100
|
+
field_lines: list[str] = []
|
|
101
|
+
|
|
102
|
+
for name, field_info in contract_cls.model_fields.items():
|
|
103
|
+
python_type = _python_type_from_annotation(field_info.annotation)
|
|
104
|
+
type_name, extra_imports = _annotation_source(python_type, optional=False)
|
|
105
|
+
imports.update(extra_imports)
|
|
106
|
+
optional = not field_info.is_required()
|
|
107
|
+
if optional:
|
|
108
|
+
type_name = f"{type_name} | None"
|
|
109
|
+
if name in pk_fields:
|
|
110
|
+
field_lines.append(f" {name}: {type_name} = Field(primary_key=True)")
|
|
111
|
+
elif field_info.default is not ...:
|
|
112
|
+
default_repr = _default_source(field_info.default, imports)
|
|
113
|
+
field_lines.append(
|
|
114
|
+
f" {name}: {type_name} = Field(default={default_repr})"
|
|
115
|
+
)
|
|
116
|
+
elif optional:
|
|
117
|
+
field_lines.append(f" {name}: {type_name} = Field(default=None)")
|
|
118
|
+
else:
|
|
119
|
+
field_lines.append(f" {name}: {type_name}")
|
|
120
|
+
|
|
121
|
+
import_lines = ["from sqlmodel import Field, SQLModel"]
|
|
122
|
+
if "datetime" in imports:
|
|
123
|
+
import_lines.insert(0, "from datetime import datetime")
|
|
124
|
+
if "date" in imports:
|
|
125
|
+
import_lines.insert(0, "from datetime import date")
|
|
126
|
+
if "Decimal" in imports:
|
|
127
|
+
import_lines.insert(0, "from decimal import Decimal")
|
|
128
|
+
# De-duplicate datetime imports when both date and datetime needed
|
|
129
|
+
if "datetime" in imports and "date" in imports:
|
|
130
|
+
import_lines = [
|
|
131
|
+
line
|
|
132
|
+
for line in import_lines
|
|
133
|
+
if line
|
|
134
|
+
not in {"from datetime import date", "from datetime import datetime"}
|
|
135
|
+
]
|
|
136
|
+
import_lines.insert(0, "from datetime import date, datetime")
|
|
137
|
+
|
|
138
|
+
body = "\n".join(field_lines) if field_lines else " pass"
|
|
139
|
+
return (
|
|
140
|
+
"\n".join(import_lines)
|
|
141
|
+
+ "\n\n\n"
|
|
142
|
+
+ f"class {model_name}(SQLModel, table=True):\n"
|
|
143
|
+
+ f' __tablename__ = "{resolved_table}"\n'
|
|
144
|
+
+ f"{body}\n"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _annotation_source(
|
|
149
|
+
python_type: type[Any], *, optional: bool
|
|
150
|
+
) -> tuple[str, set[str]]:
|
|
151
|
+
_ = optional
|
|
152
|
+
mapping = {
|
|
153
|
+
str: ("str", set()),
|
|
154
|
+
int: ("int", set()),
|
|
155
|
+
float: ("float", set()),
|
|
156
|
+
bool: ("bool", set()),
|
|
157
|
+
datetime: ("datetime", {"datetime"}),
|
|
158
|
+
date: ("date", {"date"}),
|
|
159
|
+
Decimal: ("Decimal", {"Decimal"}),
|
|
160
|
+
}
|
|
161
|
+
if python_type in mapping:
|
|
162
|
+
return mapping[python_type]
|
|
163
|
+
return ("str", set())
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _default_source(value: Any, imports: set[str]) -> str:
|
|
167
|
+
if isinstance(value, Decimal):
|
|
168
|
+
imports.add("Decimal")
|
|
169
|
+
return f"Decimal({str(value)!r})"
|
|
170
|
+
if isinstance(value, datetime):
|
|
171
|
+
imports.add("datetime")
|
|
172
|
+
return repr(value)
|
|
173
|
+
if isinstance(value, date):
|
|
174
|
+
imports.add("date")
|
|
175
|
+
return repr(value)
|
|
176
|
+
return repr(value)
|
|
177
|
+
|
|
178
|
+
|
|
85
179
|
def sqlmodel_to_contract(model_cls: type[Any]) -> dict[str, Any]:
|
|
86
180
|
"""Extract draft contract metadata from a SQLModel table class."""
|
|
87
181
|
if not _is_sqlmodel_table(model_cls):
|
|
File without changes
|