sqlmesh.cli.main
1from __future__ import annotations 2 3import os 4import sys 5import typing as t 6 7import click 8 9from sqlmesh.cli import error_handler 10from sqlmesh.cli import options as opt 11from sqlmesh.cli.example_project import ProjectTemplate, init_example_project 12from sqlmesh.core.context import Context 13from sqlmesh.utils.date import TimeLike 14 15 16@click.group(no_args_is_help=True) 17@opt.path 18@opt.config 19@click.option( 20 "--connection", 21 type=str, 22 help="The name of the connection.", 23) 24@click.option( 25 "--test-connection", 26 type=str, 27 help="The name of the connection to use for tests.", 28) 29@click.pass_context 30@error_handler 31def cli( 32 ctx: click.Context, 33 path: str, 34 config: t.Optional[str] = None, 35 connection: t.Optional[str] = None, 36 test_connection: t.Optional[str] = None, 37) -> None: 38 """SQLMesh command line tool.""" 39 if ctx.invoked_subcommand == "version": 40 return 41 42 path = os.path.abspath(path) 43 if ctx.invoked_subcommand == "init": 44 ctx.obj = path 45 return 46 47 # Delegates the execution of the --help option to the corresponding subcommand 48 if "--help" in sys.argv: 49 return 50 51 context = Context( 52 path=path, 53 config=config, 54 connection=connection, 55 test_connection=test_connection, 56 ) 57 58 if not context.models: 59 raise click.ClickException( 60 f"`{path}` doesn't seem to have any models... cd into the proper directory or specify the path with --path." 61 ) 62 63 ctx.obj = context 64 65 66@cli.command("init") 67@click.option( 68 "-t", 69 "--template", 70 type=str, 71 help="Project template. Support values: airflow, default.", 72) 73@click.pass_context 74@error_handler 75def init(ctx: click.Context, template: t.Optional[str] = None) -> None: 76 """Create a new SQLMesh repository.""" 77 try: 78 project_template = ProjectTemplate(template.lower() if template else "default") 79 except ValueError: 80 raise click.ClickException(f"Invalid project template '{template}'") 81 init_example_project(ctx.obj, template=project_template) 82 83 84@cli.command("render") 85@click.argument("model") 86@opt.start_time 87@opt.end_time 88@opt.latest_time 89@opt.expand 90@click.pass_context 91@error_handler 92def render( 93 ctx: click.Context, 94 model: str, 95 start: TimeLike, 96 end: TimeLike, 97 latest: t.Optional[TimeLike] = None, 98 expand: t.Optional[t.Union[bool, t.Iterable[str]]] = None, 99) -> None: 100 """Renders a model's query, optionally expanding referenced models.""" 101 snapshot = ctx.obj.snapshots.get(model) 102 103 if not snapshot: 104 raise click.ClickException(f"Model `{model}` not found.") 105 106 rendered = ctx.obj.render( 107 snapshot, 108 start=start, 109 end=end, 110 latest=latest, 111 expand=expand, 112 ) 113 114 sql = rendered.sql(pretty=True, dialect=ctx.obj.dialect) 115 ctx.obj.console.show_sql(sql) 116 117 118@cli.command("evaluate") 119@click.argument("model") 120@opt.start_time 121@opt.end_time 122@opt.latest_time 123@click.option( 124 "--limit", 125 type=int, 126 help="The number of rows which the query should be limited to.", 127) 128@click.pass_context 129@error_handler 130def evaluate( 131 ctx: click.Context, 132 model: str, 133 start: TimeLike, 134 end: TimeLike, 135 latest: t.Optional[TimeLike] = None, 136 limit: t.Optional[int] = None, 137) -> None: 138 """Evaluate a model and return a dataframe with a default limit of 1000.""" 139 df = ctx.obj.evaluate( 140 model, 141 start=start, 142 end=end, 143 latest=latest, 144 limit=limit, 145 ) 146 ctx.obj.console.log_success(df) 147 148 149@cli.command("format") 150@click.pass_context 151@error_handler 152def format(ctx: click.Context) -> None: 153 """Format all models in a given directory.""" 154 ctx.obj.format() 155 156 157@cli.command("diff") 158@click.argument("environment") 159@click.pass_context 160@error_handler 161def diff(ctx: click.Context, environment: t.Optional[str] = None) -> None: 162 """Show the diff between the current context and a given environment.""" 163 ctx.obj.diff(environment) 164 165 166@cli.command("plan") 167@click.argument("environment", required=False) 168@opt.start_time 169@opt.end_time 170@click.option( 171 "--create-from", 172 type=str, 173 help="The environment to create the target environment from if it doesn't exist. Default: prod.", 174) 175@click.option( 176 "--skip-tests", 177 help="Skip tests prior to generating the plan if they are defined.", 178) 179@click.option( 180 "--restate-model", 181 "-r", 182 type=str, 183 multiple=True, 184 help="Restate data for specified models and models downstream from the one specified. For production environment, all related model versions will have their intervals wiped, but only the current versions will be backfilled. For development environment, only the current model versions will be affected.", 185) 186@click.option( 187 "--no-gaps", 188 is_flag=True, 189 help="Ensure that new snapshots have no data gaps when comparing to existing snapshots for matching models in the target environment.", 190) 191@click.option( 192 "--skip-backfill", 193 is_flag=True, 194 help="Skip the backfill step.", 195) 196@click.option( 197 "--forward-only", 198 is_flag=True, 199 help="Create a plan for forward-only changes.", 200) 201@click.option( 202 "--no-prompts", 203 is_flag=True, 204 help="Disable interactive prompts for the backfill time range. Please note that if this flag is set and there are uncategorized changes, plan creation will fail.", 205) 206@click.option( 207 "--auto-apply", 208 is_flag=True, 209 help="Automatically apply the new plan after creation.", 210) 211@click.option( 212 "--no-auto-categorization", 213 is_flag=True, 214 help="Disable automatic change categorization.", 215 default=None, 216) 217@click.pass_context 218@error_handler 219def plan(ctx: click.Context, environment: t.Optional[str] = None, **kwargs: t.Any) -> None: 220 """Plan a migration of the current context's models with the given environment.""" 221 context = ctx.obj 222 restate_models = kwargs.pop("restate_model", None) 223 context.plan(environment, restate_models=restate_models, **kwargs) 224 225 226@cli.command("run") 227@click.argument("environment", required=False) 228@opt.start_time 229@opt.end_time 230@click.option("--skip-janitor", is_flag=True, help="Skip the jantitor task.") 231@click.pass_context 232@error_handler 233def run(ctx: click.Context, environment: t.Optional[str] = None, **kwargs: t.Any) -> None: 234 """Evaluates the DAG of models using the built-in scheduler.""" 235 context = ctx.obj 236 context.run(environment, **kwargs) 237 238 239@cli.command("dag") 240@opt.file 241@click.pass_context 242@error_handler 243def dag(ctx: click.Context, file: str) -> None: 244 """ 245 Renders the dag using graphviz. 246 247 This command requires a manual install of both the python and system graphviz package. 248 """ 249 ctx.obj.render_dag(file) 250 251 252@cli.command("test") 253@opt.match_pattern 254@opt.verbose 255@click.argument("tests", nargs=-1) 256@click.pass_obj 257@error_handler 258def test(obj: Context, k: t.List[str], verbose: bool, tests: t.List[str]) -> None: 259 """Run model unit tests.""" 260 # Set Python unittest verbosity level 261 result = obj.test(match_patterns=k, tests=tests, verbose=verbose) 262 if not result.wasSuccessful(): 263 exit(1) 264 265 266@cli.command("audit") 267@click.option( 268 "--model", 269 "models", 270 multiple=True, 271 help="A model to audit. Multiple models can be audited.", 272) 273@opt.start_time 274@opt.end_time 275@opt.latest_time 276@click.pass_obj 277@error_handler 278def audit( 279 obj: Context, 280 models: t.Iterator[str], 281 start: TimeLike, 282 end: TimeLike, 283 latest: t.Optional[TimeLike] = None, 284) -> None: 285 """Run audits.""" 286 obj.audit(models=models, start=start, end=end, latest=latest) 287 288 289@cli.command("fetchdf") 290@click.argument("sql") 291@click.pass_context 292@error_handler 293def fetchdf(ctx: click.Context, sql: str) -> None: 294 """Runs a sql query and displays the results.""" 295 context = ctx.obj 296 context.console.log_success(context.fetchdf(sql)) 297 298 299@cli.command("version") 300@error_handler 301def version() -> None: 302 """Print version.""" 303 try: 304 from sqlmesh import __version__ 305 306 print(__version__) 307 except ImportError: 308 print("Version is not available") 309 310 311if __name__ == "__main__": 312 cli()
cli = <Group cli>
SQLMesh command line tool.
init = <Command init>
Create a new SQLMesh repository.
render = <Command render>
Renders a model's query, optionally expanding referenced models.
evaluate = <Command evaluate>
Evaluate a model and return a dataframe with a default limit of 1000.
format = <Command format>
Format all models in a given directory.
diff = <Command diff>
Show the diff between the current context and a given environment.
plan = <Command plan>
Plan a migration of the current context's models with the given environment.
run = <Command run>
Evaluates the DAG of models using the built-in scheduler.
dag = <Command dag>
Renders the dag using graphviz.
This command requires a manual install of both the python and system graphviz package.
test = <Command test>
Run model unit tests.
audit = <Command audit>
Run audits.
fetchdf = <Command fetchdf>
Runs a sql query and displays the results.
version = <Command version>
Print version.