sqlmesh 0.209.1.dev10__py3-none-any.whl → 0.209.1.dev12__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.
- sqlmesh/_version.py +2 -2
- {sqlmesh-0.209.1.dev10.dist-info → sqlmesh-0.209.1.dev12.dist-info}/METADATA +1 -1
- {sqlmesh-0.209.1.dev10.dist-info → sqlmesh-0.209.1.dev12.dist-info}/RECORD +11 -7
- {sqlmesh-0.209.1.dev10.dist-info → sqlmesh-0.209.1.dev12.dist-info}/entry_points.txt +1 -0
- {sqlmesh-0.209.1.dev10.dist-info → sqlmesh-0.209.1.dev12.dist-info}/top_level.txt +1 -0
- sqlmesh_dbt/__init__.py +5 -0
- sqlmesh_dbt/cli.py +80 -0
- sqlmesh_dbt/console.py +8 -0
- sqlmesh_dbt/operations.py +133 -0
- {sqlmesh-0.209.1.dev10.dist-info → sqlmesh-0.209.1.dev12.dist-info}/WHEEL +0 -0
- {sqlmesh-0.209.1.dev10.dist-info → sqlmesh-0.209.1.dev12.dist-info}/licenses/LICENSE +0 -0
sqlmesh/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.209.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 209, 1, '
|
|
31
|
+
__version__ = version = '0.209.1.dev12'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 209, 1, 'dev12')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
2
|
+
sqlmesh/_version.py,sha256=7OqlZXPJ-sO1ZD5h7xeYT3AcKstkLcz3pDByvyZckQs,723
|
|
3
3
|
sqlmesh/magics.py,sha256=bEzYqXHcM0P3CjyUZ1O9arlmXAdLAhoglKbQ29fD9AE,41842
|
|
4
4
|
sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -288,7 +288,11 @@ sqlmesh/utils/pydantic.py,sha256=o_NsXbIpDqNpUA1Uc5xF0ZzoXQYYB0DfHwdRxBwXPNk,120
|
|
|
288
288
|
sqlmesh/utils/rich.py,sha256=cwQ5nJ6sgz64xHtoh6_ec7ReV5YpsOGhMtUJnwoRfEI,3549
|
|
289
289
|
sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
|
|
290
290
|
sqlmesh/utils/yaml.py,sha256=hvo5lmybYLcIx4p6CQwufS8X4MbwS60lEBnCmYJCXmU,2336
|
|
291
|
-
sqlmesh-0.209.1.
|
|
291
|
+
sqlmesh-0.209.1.dev12.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
|
|
292
|
+
sqlmesh_dbt/__init__.py,sha256=awYS5y5mz-1NUmx6i5h5NSTJ7tidRl9NC0FAnFWSF6U,350
|
|
293
|
+
sqlmesh_dbt/cli.py,sha256=Ekn77WLMmyyr31aoDoWrZp5DS0rfiddy7pNohBK8G0s,2115
|
|
294
|
+
sqlmesh_dbt/console.py,sha256=1B0B5_R1DlrEkyWVDl8G78-B6_K-ZtLPsQEhqPCfLEU,188
|
|
295
|
+
sqlmesh_dbt/operations.py,sha256=u8O5mrbX942y6lGBHMg1GPIJLTWVOUiVw35uG3okjKg,5461
|
|
292
296
|
web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
293
297
|
web/client/dist/index.html,sha256=SXykdSRNgrT1k6I2dPZPEfpxPjIsi8-yVFijt-naSA4,5472
|
|
294
298
|
web/client/dist/assets/Audits-Jm353fhk.js,sha256=ry6b5IKT3hLAfD5C3T2BqxulfauEV0n0YZ2vsP4eQ_U,1041
|
|
@@ -406,8 +410,8 @@ web/server/api/endpoints/models.py,sha256=kwj0s7uve3iZSMfmjkoPVMFMeY1sD0peTeyrWf
|
|
|
406
410
|
web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
|
|
407
411
|
web/server/api/endpoints/plan.py,sha256=bbbY50W_2MsZSTxOHWMKz0tbIm75nsRSlPy8GI2fg9Q,9306
|
|
408
412
|
web/server/api/endpoints/table_diff.py,sha256=SCy3-pr5x6bEEiOaZGCDbiHQhpgxwmnz3Acqa2Ie6jI,2090
|
|
409
|
-
sqlmesh-0.209.1.
|
|
410
|
-
sqlmesh-0.209.1.
|
|
411
|
-
sqlmesh-0.209.1.
|
|
412
|
-
sqlmesh-0.209.1.
|
|
413
|
-
sqlmesh-0.209.1.
|
|
413
|
+
sqlmesh-0.209.1.dev12.dist-info/METADATA,sha256=M3xduNBEn62vHm2RLj8dwbolcTWTz77Rk0Mlu3z_tOY,26686
|
|
414
|
+
sqlmesh-0.209.1.dev12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
415
|
+
sqlmesh-0.209.1.dev12.dist-info/entry_points.txt,sha256=sHAf6tQczIM8xZoduN4qaUjV7QEPVUUW_LCT8EDUMv4,155
|
|
416
|
+
sqlmesh-0.209.1.dev12.dist-info/top_level.txt,sha256=RQ-33FPe2IgL0rgossAfJkCRtqslz9b7wFARqiWLC5Q,24
|
|
417
|
+
sqlmesh-0.209.1.dev12.dist-info/RECORD,,
|
sqlmesh_dbt/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Note: `sqlmesh_dbt` is deliberately in its own package from `sqlmesh` to avoid the upfront time overhead
|
|
2
|
+
# that comes from `import sqlmesh`
|
|
3
|
+
#
|
|
4
|
+
# Obviously we still have to `import sqlmesh` at some point but this allows us to defer it until needed,
|
|
5
|
+
# which means we can make the CLI feel more responsive by being able to output something immediately
|
sqlmesh_dbt/cli.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
import sys
|
|
3
|
+
import click
|
|
4
|
+
from sqlmesh_dbt.operations import DbtOperations, create
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _get_dbt_operations(ctx: click.Context) -> DbtOperations:
|
|
8
|
+
if not isinstance(ctx.obj, DbtOperations):
|
|
9
|
+
raise ValueError(f"Unexpected click context object: {type(ctx.obj)}")
|
|
10
|
+
return ctx.obj
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
@click.pass_context
|
|
15
|
+
def dbt(ctx: click.Context) -> None:
|
|
16
|
+
"""
|
|
17
|
+
An ELT tool for managing your SQL transformations and data models, powered by the SQLMesh engine.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
if "--help" in sys.argv:
|
|
21
|
+
# we dont need to import sqlmesh/load the project for CLI help
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
# TODO: conditionally call create() if there are times we dont want/need to import sqlmesh and load a project
|
|
25
|
+
ctx.obj = create()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dbt.command()
|
|
29
|
+
@click.option("-s", "-m", "--select", "--models", "--model", help="Specify the nodes to include.")
|
|
30
|
+
@click.option(
|
|
31
|
+
"-f",
|
|
32
|
+
"--full-refresh",
|
|
33
|
+
help="If specified, dbt will drop incremental models and fully-recalculate the incremental table from the model definition.",
|
|
34
|
+
)
|
|
35
|
+
@click.pass_context
|
|
36
|
+
def run(ctx: click.Context, select: t.Optional[str], full_refresh: bool) -> None:
|
|
37
|
+
"""Compile SQL and execute against the current target database."""
|
|
38
|
+
_get_dbt_operations(ctx).run(select=select, full_refresh=full_refresh)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dbt.command(name="list")
|
|
42
|
+
@click.pass_context
|
|
43
|
+
def list_(ctx: click.Context) -> None:
|
|
44
|
+
"""List the resources in your project"""
|
|
45
|
+
_get_dbt_operations(ctx).list_()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dbt.command(name="ls", hidden=True) # hidden alias for list
|
|
49
|
+
@click.pass_context
|
|
50
|
+
def ls(ctx: click.Context) -> None:
|
|
51
|
+
"""List the resources in your project"""
|
|
52
|
+
ctx.forward(list_)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _not_implemented(name: str) -> None:
|
|
56
|
+
@dbt.command(name=name)
|
|
57
|
+
def _not_implemented() -> None:
|
|
58
|
+
"""Not implemented"""
|
|
59
|
+
click.echo(f"dbt {name} not implemented")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
for subcommand in (
|
|
63
|
+
"build",
|
|
64
|
+
"clean",
|
|
65
|
+
"clone",
|
|
66
|
+
"compile",
|
|
67
|
+
"debug",
|
|
68
|
+
"deps",
|
|
69
|
+
"docs",
|
|
70
|
+
"init",
|
|
71
|
+
"parse",
|
|
72
|
+
"retry",
|
|
73
|
+
"run-operation",
|
|
74
|
+
"seed",
|
|
75
|
+
"show",
|
|
76
|
+
"snapshot",
|
|
77
|
+
"source",
|
|
78
|
+
"test",
|
|
79
|
+
):
|
|
80
|
+
_not_implemented(subcommand)
|
sqlmesh_dbt/console.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import typing as t
|
|
3
|
+
from rich.progress import Progress
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
if t.TYPE_CHECKING:
|
|
7
|
+
# important to gate these to be able to defer importing sqlmesh until we need to
|
|
8
|
+
from sqlmesh.core.context import Context
|
|
9
|
+
from sqlmesh.dbt.project import Project
|
|
10
|
+
from sqlmesh_dbt.console import DbtCliConsole
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DbtOperations:
|
|
14
|
+
def __init__(self, sqlmesh_context: Context, dbt_project: Project):
|
|
15
|
+
self.context = sqlmesh_context
|
|
16
|
+
self.project = dbt_project
|
|
17
|
+
|
|
18
|
+
def list_(self) -> None:
|
|
19
|
+
for _, model in self.context.models.items():
|
|
20
|
+
self.console.print(model.name)
|
|
21
|
+
|
|
22
|
+
def run(self, select: t.Optional[str] = None, full_refresh: bool = False) -> None:
|
|
23
|
+
# A dbt run both updates data and changes schemas and has no way of rolling back so more closely maps to a SQLMesh forward-only plan
|
|
24
|
+
# TODO: if --full-refresh specified, mark incrementals as breaking instead of forward_only?
|
|
25
|
+
|
|
26
|
+
# TODO: we need to either convert DBT selector syntax to SQLMesh selector syntax
|
|
27
|
+
# or make the model selection engine configurable
|
|
28
|
+
select_models = None
|
|
29
|
+
if select:
|
|
30
|
+
if "," in select:
|
|
31
|
+
select_models = select.split(",")
|
|
32
|
+
else:
|
|
33
|
+
select_models = select.split(" ")
|
|
34
|
+
|
|
35
|
+
self.context.plan(
|
|
36
|
+
select_models=select_models,
|
|
37
|
+
no_auto_categorization=True, # everything is breaking / foward-only
|
|
38
|
+
run=True,
|
|
39
|
+
no_diff=True,
|
|
40
|
+
no_prompts=True,
|
|
41
|
+
auto_apply=True,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def console(self) -> DbtCliConsole:
|
|
46
|
+
console = self.context.console
|
|
47
|
+
from sqlmesh_dbt.console import DbtCliConsole
|
|
48
|
+
|
|
49
|
+
if not isinstance(console, DbtCliConsole):
|
|
50
|
+
raise ValueError(f"Expecting dbt cli console, got: {console}")
|
|
51
|
+
|
|
52
|
+
return console
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def create(
|
|
56
|
+
project_dir: t.Optional[Path] = None, profiles_dir: t.Optional[Path] = None, debug: bool = False
|
|
57
|
+
) -> DbtOperations:
|
|
58
|
+
with Progress(transient=True) as progress:
|
|
59
|
+
# Indeterminate progress bar before SQLMesh import to provide feedback to the user that something is indeed happening
|
|
60
|
+
load_task_id = progress.add_task("Loading engine", total=None)
|
|
61
|
+
|
|
62
|
+
from sqlmesh import configure_logging
|
|
63
|
+
from sqlmesh.core.context import Context
|
|
64
|
+
from sqlmesh.dbt.loader import sqlmesh_config, DbtLoader
|
|
65
|
+
from sqlmesh.core.console import set_console
|
|
66
|
+
from sqlmesh_dbt.console import DbtCliConsole
|
|
67
|
+
from sqlmesh.utils.errors import SQLMeshError
|
|
68
|
+
|
|
69
|
+
configure_logging(force_debug=debug)
|
|
70
|
+
set_console(DbtCliConsole())
|
|
71
|
+
|
|
72
|
+
progress.update(load_task_id, description="Loading project", total=None)
|
|
73
|
+
|
|
74
|
+
# inject default start date if one is not specified to prevent the user from having to do anything
|
|
75
|
+
_inject_default_start_date(project_dir)
|
|
76
|
+
|
|
77
|
+
config = sqlmesh_config(
|
|
78
|
+
project_root=project_dir,
|
|
79
|
+
# do we want to use a local duckdb for state?
|
|
80
|
+
# warehouse state has a bunch of overhead to initialize, is slow for ongoing operations and will create tables that perhaps the user was not expecting
|
|
81
|
+
# on the other hand, local state is not portable
|
|
82
|
+
state_connection=None,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
sqlmesh_context = Context(
|
|
86
|
+
config=config,
|
|
87
|
+
load=True,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# this helps things which want a default project-level start date, like the "effective from date" for forward-only plans
|
|
91
|
+
if not sqlmesh_context.config.model_defaults.start:
|
|
92
|
+
min_start_date = min(
|
|
93
|
+
(
|
|
94
|
+
model.start
|
|
95
|
+
for model in sqlmesh_context.models.values()
|
|
96
|
+
if model.start is not None
|
|
97
|
+
),
|
|
98
|
+
default=None,
|
|
99
|
+
)
|
|
100
|
+
sqlmesh_context.config.model_defaults.start = min_start_date
|
|
101
|
+
|
|
102
|
+
dbt_loader = sqlmesh_context._loaders[0]
|
|
103
|
+
if not isinstance(dbt_loader, DbtLoader):
|
|
104
|
+
raise SQLMeshError(f"Unexpected loader type: {type(dbt_loader)}")
|
|
105
|
+
|
|
106
|
+
# so that DbtOperations can query information from the DBT project files in order to invoke SQLMesh correctly
|
|
107
|
+
dbt_project = dbt_loader._projects[0]
|
|
108
|
+
|
|
109
|
+
return DbtOperations(sqlmesh_context, dbt_project)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _inject_default_start_date(project_dir: t.Optional[Path] = None) -> None:
|
|
113
|
+
"""
|
|
114
|
+
SQLMesh needs a start date to as the starting point for calculating intervals on incremental models
|
|
115
|
+
|
|
116
|
+
Rather than forcing the user to update their config manually or having a default that is not saved between runs,
|
|
117
|
+
we can inject it automatically to the dbt_project.yml file
|
|
118
|
+
"""
|
|
119
|
+
from sqlmesh.dbt.project import PROJECT_FILENAME, load_yaml
|
|
120
|
+
from sqlmesh.utils.yaml import dump
|
|
121
|
+
from sqlmesh.utils.date import yesterday_ds
|
|
122
|
+
|
|
123
|
+
project_yaml_path = (project_dir or Path.cwd()) / PROJECT_FILENAME
|
|
124
|
+
if project_yaml_path.exists():
|
|
125
|
+
loaded_project_file = load_yaml(project_yaml_path)
|
|
126
|
+
start_date_keys = ("start", "+start")
|
|
127
|
+
if "models" in loaded_project_file and all(
|
|
128
|
+
k not in loaded_project_file["models"] for k in start_date_keys
|
|
129
|
+
):
|
|
130
|
+
loaded_project_file["models"]["+start"] = yesterday_ds()
|
|
131
|
+
# todo: this may format the file differently, is that acceptable?
|
|
132
|
+
with project_yaml_path.open("w") as f:
|
|
133
|
+
dump(loaded_project_file, f)
|
|
File without changes
|
|
File without changes
|