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 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.dev10'
32
- __version_tuple__ = version_tuple = (0, 209, 1, 'dev10')
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.209.1.dev10
3
+ Version: 0.209.1.dev12
4
4
  Summary: Next-generation data transformation framework
5
5
  Author-email: "TobikoData Inc." <engineering@tobikodata.com>
6
6
  License: Apache License
@@ -1,5 +1,5 @@
1
1
  sqlmesh/__init__.py,sha256=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
2
- sqlmesh/_version.py,sha256=Igshe-vepS3oVl2sTH0hj1iCEG61O35goUT34bEh2t4,723
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.dev10.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
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.dev10.dist-info/METADATA,sha256=SYcGEzmGQzEPLJIypLUOFqWWZDiBQxYqWUENLU0gp2I,26686
410
- sqlmesh-0.209.1.dev10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
411
- sqlmesh-0.209.1.dev10.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
412
- sqlmesh-0.209.1.dev10.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
413
- sqlmesh-0.209.1.dev10.dist-info/RECORD,,
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,,
@@ -1,4 +1,5 @@
1
1
  [console_scripts]
2
2
  sqlmesh = sqlmesh.cli.main:cli
3
3
  sqlmesh_cicd = sqlmesh.cicd.bot:bot
4
+ sqlmesh_dbt = sqlmesh_dbt.cli:dbt
4
5
  sqlmesh_lsp = sqlmesh.lsp.main:main
@@ -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,8 @@
1
+ from sqlmesh.core.console import TerminalConsole
2
+
3
+
4
+ class DbtCliConsole(TerminalConsole):
5
+ # TODO: build this out
6
+
7
+ def print(self, msg: str) -> None:
8
+ return self._print(msg)
@@ -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)