weaverstack 0.1.1__py3-none-any.whl
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.
- weaver/__init__.py +59 -0
- weaver/build_bundle/__init__.py +109 -0
- weaver/build_bundle/aliases.py +325 -0
- weaver/build_bundle/bundle.py +359 -0
- weaver/build_bundle/catalogue_actions.py +275 -0
- weaver/build_bundle/changes.py +186 -0
- weaver/build_bundle/endpoints.py +83 -0
- weaver/build_bundle/executors/__init__.py +69 -0
- weaver/build_bundle/executors/alias.py +202 -0
- weaver/build_bundle/executors/base.py +132 -0
- weaver/build_bundle/executors/folder.py +71 -0
- weaver/build_bundle/executors/load_file.py +205 -0
- weaver/build_bundle/executors/spark_case.py +26 -0
- weaver/build_bundle/executors/spark_schema.py +60 -0
- weaver/build_bundle/executors/spark_sql.py +59 -0
- weaver/build_bundle/executors/spark_sql_batch.py +57 -0
- weaver/build_bundle/executors/spark_table.py +213 -0
- weaver/build_bundle/executors/sql_endpoint_refresh.py +34 -0
- weaver/build_bundle/executors/tsql.py +81 -0
- weaver/build_bundle/incremental.py +288 -0
- weaver/build_bundle/installer.py +384 -0
- weaver/build_bundle/models.py +288 -0
- weaver/build_bundle/payloads.py +34 -0
- weaver/build_bundle/physical.py +625 -0
- weaver/build_bundle/planner.py +389 -0
- weaver/build_bundle/prune.py +620 -0
- weaver/build_bundle/report.py +108 -0
- weaver/build_bundle/stages.py +196 -0
- weaver/build_bundle/targets.py +272 -0
- weaver/build_bundle/workflow.py +585 -0
- weaver/catalogue/__init__.py +73 -0
- weaver/catalogue/builtin.py +238 -0
- weaver/catalogue/claims.py +121 -0
- weaver/catalogue/projection.py +437 -0
- weaver/catalogue/reader.py +152 -0
- weaver/catalogue/reconcile.py +231 -0
- weaver/catalogue/render.py +410 -0
- weaver/catalogue/state.py +660 -0
- weaver/catalogue/tables.py +648 -0
- weaver/config.py +178 -0
- weaver/declaration/__init__.py +171 -0
- weaver/declaration/columns.py +223 -0
- weaver/declaration/ddl.py +266 -0
- weaver/declaration/dependencies.py +544 -0
- weaver/declaration/graph.py +240 -0
- weaver/declaration/item_dependencies.py +292 -0
- weaver/declaration/load.py +191 -0
- weaver/declaration/metadata.py +1405 -0
- weaver/declaration/model.py +448 -0
- weaver/declaration/references.py +294 -0
- weaver/declaration/repository.py +959 -0
- weaver/declaration/schemas.py +135 -0
- weaver/declaration/source.py +674 -0
- weaver/declaration/spark_load.py +759 -0
- weaver/declaration/sql_shaping.py +591 -0
- weaver/declaration/templates/ddl/declared_create_table.sql +64 -0
- weaver/declaration/templates/ddl/infer_create_table.sql +97 -0
- weaver/declaration/templates/ddl/metadata_column_validation.sql +30 -0
- weaver/declaration/templates/load/column_metadata.sql +40 -0
- weaver/declaration/templates/load/full_replace_body.sql +21 -0
- weaver/declaration/templates/load/install_load_procedure.sql +27 -0
- weaver/declaration/templates/load/load_procedure.sql +48 -0
- weaver/declaration/templates/load/primary_key_body.sql +113 -0
- weaver/declaration/tsql_ddl.py +468 -0
- weaver/declaration/tsql_load.py +417 -0
- weaver/declaration/warehouse_type_mapping.yml +93 -0
- weaver/diagnostics.py +247 -0
- weaver/errors.py +61 -0
- weaver/etl.py +469 -0
- weaver/fabric/__init__.py +107 -0
- weaver/fabric/auth.py +137 -0
- weaver/fabric/capacity.py +143 -0
- weaver/fabric/client.py +147 -0
- weaver/fabric/environment.py +460 -0
- weaver/fabric/livy.py +478 -0
- weaver/fabric/notebooks.py +201 -0
- weaver/fabric/onelake.py +263 -0
- weaver/fabric/resolution.py +344 -0
- weaver/fabric/resources.py +245 -0
- weaver/fabric/session.py +148 -0
- weaver/fabric/shortcuts.py +120 -0
- weaver/fabric/sql.py +118 -0
- weaver/fabric/store.py +198 -0
- weaver/initialise.py +209 -0
- weaver/lakehouse.py +386 -0
- weaver/load.py +474 -0
- weaver/load_execution.py +483 -0
- weaver/load_plan.py +912 -0
- weaver/load_report.py +330 -0
- weaver/load_resolution.py +386 -0
- weaver/locations.py +164 -0
- weaver/objects.py +392 -0
- weaver/operations.py +757 -0
- weaver/physical_wipe.py +369 -0
- weaver/push.py +76 -0
- weaver/resolution.py +292 -0
- weaver/runtime/__init__.py +30 -0
- weaver/runtime/folder_load.py +402 -0
- weaver/runtime/load_contract.py +245 -0
- weaver/runtime/load_result.py +104 -0
- weaver/runtime/spark_load.py +152 -0
- weaver/runtime/table_load.py +497 -0
- weaver/spark/__init__.py +49 -0
- weaver/spark/catalogue.py +245 -0
- weaver/spark/destination.py +195 -0
- weaver/spark/session.py +84 -0
- weaver/spark/tokens.py +138 -0
- weaver/sql/__init__.py +40 -0
- weaver/sql/authentication.py +38 -0
- weaver/sql/connection.py +90 -0
- weaver/sql/errors.py +25 -0
- weaver/sql/execution.py +123 -0
- weaver/sql/pool.py +174 -0
- weaver/sql/wipe.py +156 -0
- weaver/store.py +209 -0
- weaver/targets.py +257 -0
- weaver/task_logging.py +215 -0
- weaver/unbind.py +74 -0
- weaver/workspaces.py +175 -0
- weaver_cli/__init__.py +12 -0
- weaver_cli/__main__.py +7 -0
- weaver_cli/main.py +626 -0
- weaverstack-0.1.1.dist-info/METADATA +113 -0
- weaverstack-0.1.1.dist-info/RECORD +127 -0
- weaverstack-0.1.1.dist-info/WHEEL +4 -0
- weaverstack-0.1.1.dist-info/entry_points.txt +2 -0
- weaverstack-0.1.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""Generated load definitions — the *load* form of a Weaver document source.
|
|
2
|
+
|
|
3
|
+
The sibling of :mod:`weaver.declaration.ddl`, and the division between them is
|
|
4
|
+
the one Weaver is built on: build creates structure, load puts rows in it. A
|
|
5
|
+
source knows how to produce both, because it alone holds its language, kind, ID
|
|
6
|
+
and validated body — and neither generator ever reopens a repository.
|
|
7
|
+
|
|
8
|
+
.. code-block:: text
|
|
9
|
+
|
|
10
|
+
SourceDocument
|
|
11
|
+
knows the parsed contract, source body and language
|
|
12
|
+
creates the executable load definition
|
|
13
|
+
|
|
14
|
+
LoadArtefact
|
|
15
|
+
carries the completed payload into claiming, planning,
|
|
16
|
+
installation, registration and pruning
|
|
17
|
+
|
|
18
|
+
:class:`weaver.etl.LoadArtefact` remains the lifecycle object and does not
|
|
19
|
+
generate itself. It asks for a payload and carries what it gets, which is why
|
|
20
|
+
replacing what this module returns moves exactly the artefacts whose bytes
|
|
21
|
+
changed and nothing else.
|
|
22
|
+
|
|
23
|
+
**Neither generated load is finished here**, and that is the shape both share
|
|
24
|
+
rather than a limitation of either. What a load writes are the *physical*
|
|
25
|
+
target's columns, and they are not knowable while the target is still a
|
|
26
|
+
declaration: a Warehouse table and a Spark SQL table may each leave their shape
|
|
27
|
+
to be inferred at build. So generation produces something destination-free and
|
|
28
|
+
incomplete, and installation finishes it against the table that now exists:
|
|
29
|
+
|
|
30
|
+
.. code-block:: text
|
|
31
|
+
|
|
32
|
+
create_load() a destination-free instruction
|
|
33
|
+
→ the target DDL is built
|
|
34
|
+
→ the installer reads the physical target's columns
|
|
35
|
+
→ the installer renders the executable definition
|
|
36
|
+
→ destination tokens are resolved
|
|
37
|
+
→ the runnable artefact is installed
|
|
38
|
+
|
|
39
|
+
The two differ only in where that rendering happens. A Warehouse load is an
|
|
40
|
+
*installer script*: it carries the assembly with it and runs it server-side,
|
|
41
|
+
reading ``sys.columns`` and creating the procedure in one execution. A Spark SQL
|
|
42
|
+
load is an *instruction*, because Spark has no way to assemble a program from
|
|
43
|
+
inside one — so the ``load_file`` executor reads the built table's schema,
|
|
44
|
+
renders the program and writes it down.
|
|
45
|
+
|
|
46
|
+
Which sources own a load, and in what form:
|
|
47
|
+
|
|
48
|
+
.. code-block:: text
|
|
49
|
+
|
|
50
|
+
Warehouse table (T-SQL) an installer script for [_].[Load S.N]
|
|
51
|
+
Lakehouse table (Spark SQL) an instruction the installer renders
|
|
52
|
+
Lakehouse table (Python) the authored module itself
|
|
53
|
+
Folder (Python) the authored module itself
|
|
54
|
+
|
|
55
|
+
The two Python forms are not generated at all, and that is the honest answer
|
|
56
|
+
rather than a gap: the author's module *is* the executable artefact, so it is
|
|
57
|
+
deployed verbatim and signed by its own bytes. It also needs no second phase —
|
|
58
|
+
a Python load reads its target's columns when it runs, which is the same
|
|
59
|
+
question answered at the same place. A view owns no load; its definition is its
|
|
60
|
+
query, so there is nothing to run.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
from __future__ import annotations
|
|
64
|
+
|
|
65
|
+
from dataclasses import dataclass
|
|
66
|
+
from typing import TYPE_CHECKING
|
|
67
|
+
|
|
68
|
+
from .metadata import SPARK_SQL, SQL, TABLE
|
|
69
|
+
|
|
70
|
+
if TYPE_CHECKING:
|
|
71
|
+
from .source import SourceDocument
|
|
72
|
+
|
|
73
|
+
#: The T-SQL load generator's version, and the Spark SQL one's. Separate because
|
|
74
|
+
#: the two evolve independently: a change to the Spark DML has no bearing on what
|
|
75
|
+
#: a Warehouse procedure should contain, and bumping one must not invalidate the
|
|
76
|
+
#: other's artefacts. Each is a *signature salt*, never part of an identity.
|
|
77
|
+
#:
|
|
78
|
+
#: **Raise one whenever its generated output changes.** A signature is the
|
|
79
|
+
#: source's plus this number, so an edit to a generator that leaves both alone
|
|
80
|
+
#: produces different bytes with an unchanged signature — and incremental
|
|
81
|
+
#: selection, correctly, rebuilds nothing. The estate then keeps running the
|
|
82
|
+
#: previous generation's artefacts, which is the failure this exists to prevent
|
|
83
|
+
#: and which cost a Fabric round trip to notice.
|
|
84
|
+
TSQL_LOAD_VERSION = 5
|
|
85
|
+
SPARK_LOAD_VERSION = 7
|
|
86
|
+
|
|
87
|
+
#: What object a generated load installs, in the catalogue's vocabulary. A
|
|
88
|
+
#: Warehouse load is a stored procedure; a Lakehouse load is a file in the
|
|
89
|
+
#: deployed runtime tree.
|
|
90
|
+
PROCEDURE_OBJECT = "stored_procedure"
|
|
91
|
+
FILE_OBJECT = "file"
|
|
92
|
+
|
|
93
|
+
TSQL_LOAD_EXTENSION = ".sql"
|
|
94
|
+
SPARK_LOAD_EXTENSION = ".spark.sql"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass(frozen=True)
|
|
98
|
+
class GeneratedLoad:
|
|
99
|
+
"""One source's generated load payload — installable, not yet executable.
|
|
100
|
+
|
|
101
|
+
``payload`` is what the bundle carries and what the installer is handed. It
|
|
102
|
+
is deliberately *not* a finished program: a Warehouse load is a script that
|
|
103
|
+
assembles the procedure server-side, and a Spark SQL load is an instruction
|
|
104
|
+
the executor renders once it can see the built table. Calling it a completed
|
|
105
|
+
executable definition would misdescribe both, and invite a reader to write
|
|
106
|
+
the file down unchanged.
|
|
107
|
+
|
|
108
|
+
``template_version`` is the generator's version, carried out so the artefact
|
|
109
|
+
layer can salt a signature with it without knowing which generator ran. That
|
|
110
|
+
is what makes a change to load generation rebuild exactly the loads it
|
|
111
|
+
changed, and leave deployed Python — signed by its own bytes — alone.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
object_type: str
|
|
115
|
+
payload: bytes
|
|
116
|
+
template_version: int
|
|
117
|
+
extension: str
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def generate_load(document: "SourceDocument") -> GeneratedLoad:
|
|
121
|
+
"""The installable load payload for one validated source.
|
|
122
|
+
|
|
123
|
+
Only a table has one. A Folder's load is its authored module and a View has
|
|
124
|
+
no load at all, so neither reaches here — :func:`has_generated_load` is the
|
|
125
|
+
question to ask first.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
if document.kind != TABLE:
|
|
129
|
+
raise NotImplementedError(
|
|
130
|
+
f"{document.relative_path}: a {document.kind} has no generated load"
|
|
131
|
+
)
|
|
132
|
+
if document.language == SQL:
|
|
133
|
+
return _tsql_load(document)
|
|
134
|
+
if document.language == SPARK_SQL:
|
|
135
|
+
return _spark_load(document)
|
|
136
|
+
raise NotImplementedError(
|
|
137
|
+
f"{document.relative_path}: a {document.language} table's load is its "
|
|
138
|
+
"authored module, which is deployed rather than generated"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def has_generated_load(document: "SourceDocument") -> bool:
|
|
143
|
+
"""Whether this source's load is generated rather than deployed verbatim."""
|
|
144
|
+
|
|
145
|
+
return document.kind == TABLE and document.language in (SQL, SPARK_SQL)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _tsql_load(document: "SourceDocument") -> GeneratedLoad:
|
|
149
|
+
from ..etl import load_procedure_name
|
|
150
|
+
from .tsql_load import generate_tsql_load_script
|
|
151
|
+
|
|
152
|
+
content = generate_tsql_load_script(
|
|
153
|
+
document.document,
|
|
154
|
+
document.sql_body or "",
|
|
155
|
+
procedure_name=load_procedure_name(document.object_id),
|
|
156
|
+
)
|
|
157
|
+
return GeneratedLoad(
|
|
158
|
+
object_type=PROCEDURE_OBJECT,
|
|
159
|
+
payload=content.encode("utf-8"),
|
|
160
|
+
template_version=TSQL_LOAD_VERSION,
|
|
161
|
+
extension=TSQL_LOAD_EXTENSION,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _spark_load(document: "SourceDocument") -> GeneratedLoad:
|
|
166
|
+
from .spark_load import generate_spark_load_instruction
|
|
167
|
+
|
|
168
|
+
# An instruction, not the program: the columns a load writes are the built
|
|
169
|
+
# table's, and a Spark SQL table may infer its schema at build. The
|
|
170
|
+
# installer reads them and renders the file into place — the same two-phase
|
|
171
|
+
# shape the Warehouse load uses with sys.columns.
|
|
172
|
+
content = generate_spark_load_instruction(
|
|
173
|
+
document.document, document.sql_body or ""
|
|
174
|
+
)
|
|
175
|
+
return GeneratedLoad(
|
|
176
|
+
object_type=FILE_OBJECT,
|
|
177
|
+
payload=content.encode("utf-8"),
|
|
178
|
+
template_version=SPARK_LOAD_VERSION,
|
|
179
|
+
extension=SPARK_LOAD_EXTENSION,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
__all__ = [
|
|
184
|
+
"FILE_OBJECT",
|
|
185
|
+
"PROCEDURE_OBJECT",
|
|
186
|
+
"SPARK_LOAD_VERSION",
|
|
187
|
+
"TSQL_LOAD_VERSION",
|
|
188
|
+
"GeneratedLoad",
|
|
189
|
+
"generate_load",
|
|
190
|
+
"has_generated_load",
|
|
191
|
+
]
|